How to provide frontend with JSON web token after server authentication?

前端 未结 4 605
南旧
南旧 2021-02-04 04:57

So far I have only dealt with server-rendered apps, where after a user logs in via username/password or using an OAuth provider (Facebook etc.), the server just sets a session c

4条回答
  •  无人共我
    2021-02-04 05:36

    When you get a token from any passport authentication sites you have to save the token in your browser's localStorage. The Dispatch is Redux's Middleware. Ignore dispatch if you don't use redux in your app. you can just use setState here (A bit weird without redux).

    Client-side:

    Here's something similar API of mine, which returns token.

    saving tokens

    axios.post(`${ROOT_URL}/api/signin`, { email, password })
            .then(response => {
    
                dispatch({ type: AUTH_USER }); //setting state (Redux's Style)
                localStorage.setItem('token', response.data.token); //saving token
                browserHistory.push('/home'); //pushes back the user after storing token
            })
            .catch(error => {
                var ERROR_DATA;
                try{
                    ERROR_DATA = JSON.parse(error.response.request.response).error;
                }
                catch(error) {
                    ERROR_DATA = 'SOMETHING WENT WRONG';
                }
                dispatch(authError(ERROR_DATA)); //throw error (Redux's Style)
            });
    

    So When you make some authenticated requests,you have to attach the token with the request in this form.

    authenticated requests

    axios.get(`${ROOT_URL}/api/blog/${blogId}`, {
            headers: { authorization: localStorage.getItem('token') } 
    //take the token from localStorage and put it on headers ('authorization is my own header')
        })
            .then(response => {
                dispatch({
                    type: FETCH_BLOG,
                    payload: response.data
                });
            })
            .catch(error => {
                console.log(error);
            });
    

    Here's my index.js: The token is checked each and everytime, so even if the browser got refreshed, you can still set the state.

    checks if the user is authenticated

    const token = localStorage.getItem('token');
    
    if (token) {
       store.dispatch({ type: AUTH_USER })
    }
    
    ReactDOM.render(
      
        
           
    ..
    ..
    ..
          
    //ignore this requireAuth - that's another component, checks if a user is authenticated. if not pushes to the index route
          
        
      
      , document.querySelector('.container'));
    

    All that dispach actions does is it sets the state.

    my reducer file(Redux only) else you can just use setState() in your index route file to provide the state to the whole application. Every time the dispatch is called, it runs a similar reducer file like this which sets the state.

    setting the state

    import { AUTH_USER, UNAUTH_USER, AUTH_ERROR } from '../actions/types';
    
    export default function(state = {}, action) {
        switch(action.type) {
            case AUTH_USER:
                return { ...state, error: '', authenticated: true };
            case UNAUTH_USER:
                return { ...state, error: '', authenticated: false };
            case AUTH_ERROR:
                return { ...state, error: action.payload };
        }
    
        return state;
    } //you can skip this and use setState() in your index route instead
    

    Delete the token from your localStorage to logout.

    caution: Use any different name rather than token to save the token in your browser's localStorage

    Server-Side:

    considering your passport services file. You must set the header search. Here's passport.js

    const passport = require('passport');
    const ExtractJwt = require('passport-jwt').ExtractJwt;
    const JwtStrategy = require('passport-jwt').Strategy;
    ..
    .. 
    ..
    ..
    const jwtOptions = {
    jwtFromRequest: ExtractJwt.fromHeader('authorization'), //client's side must specify this header
    secretOrKey: config.secret
    };
    
    const JWTVerify = new JwtStrategy(jwtOptions, (payload, done) => {
        User.findById(payload._id, (err, user) => {
            if (err) { done(err, null); }
    
            if (user) {
                done(null, user);
            } else {
                done(null, false);
            }
        });
    });
    
    passport.use(JWTVerify);
    

    In my router.js

    const passportService = require('./services/passport');
    const requireAuthentication = passport.authenticate('jwt', { session: false });
    ..
    ..
    ..
    //for example the api router the above react action used
    app.get('/api/blog/:blogId', requireAuthentication, BlogController.getBlog);
    

提交回复
热议问题