编辑用户数据后如何更新passportJWT数据?

时间:2019-05-14 18:57:00

标签: node.js reactjs react-redux

我正在使用NodeJS,Express,React和Redux进行项目。

我在导航中显示当前登录用户的用户名。
我目前正在编码用户数据更新,但是在编辑数据后,用户名在导航栏中不会更改。
我知道这是因为登录用户的令牌会记住旧数据。我使用PassportJWT。编辑用户数据(editAdmin操作)后如何在Passport中更新我的用户数据?

快速路线更新用户数据:

    const saltRounds = 10;

    Admin.findOne({ name: req.params.name }, (err, admin) => {
        if (err) {
            res.status(400).json({
                errors: err
            })
        }

        if (admin) {
            bcrypt.hash(req.body.password, saltRounds, function (err, hash) {
                if (err) {
                    res.status(400).json({
                        errors: err
                    })
                }
                let hashPassword = hash;

                const updateAdmin = {
                    name: req.body.name,
                    email: req.body.email,
                    password: req.body.password === "" ? admin.password : hashPassword,
                    role: req.body.role
                }

                Admin.findOneAndUpdate(
                    { _id: admin.id },
                    { $set: updateAdmin },
                    { new: true, useFindAndModify: false }
                ).then(admin => res.json(admin))
                    .catch(err => res.json({
                        errors: err
                    }));

            });
        }
    })
})

Navbar.js

import React from 'react';
import { Link } from 'react-router-dom';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { logoutUser } from '../../actions/authActions';

class Navbar extends React.Component {

    render() {
        const { isAuthenticated, user } = this.props.auth;

        return (
            <nav className="navbar is-dark" role="navigation" aria-label="main navigation">
                <div className="navbar-brand">
                    <Link to="/" className="navbar-item">
                        <h2>ADMIN PANEL</h2>
                    </Link>

                    <button className="navbar-burger burger" aria-label="menu" aria-expanded="false"
                        data-target="navbarBasicExample">
                        <span aria-hidden="true"></span>
                        <span aria-hidden="true"></span>
                        <span aria-hidden="true"></span>
                    </button>
                </div>

                <div id="navbarBasicExample" className="navbar-menu">
                    <div className="navbar-start">
                        {isAuthenticated && <Link to="/admins" className="navbar-item"> Admins List</Link>}
                    </div>

                    {!isAuthenticated &&
                        <div className="navbar-end">
                            <div className="navbar-item">
                                <div className="buttons">
                                    {/* <a href="#" className="button is-danger">
                                    <strong>Sign up</strong>
                                </a> */}
                                    <Link className="button is-danger" to="/login">Login</Link>
                                </div>
                            </div>
                        </div>
                    }

                    {isAuthenticated &&
                        <div className="navbar-end">
                            <div className="navbar-item">
                                <figure className="image is-24x24">
                                    <img className="is-rounded" src={user.avatar} alt="profile-img" />
                                </figure>
                                <p className="navbar-item has-text-white">{user.name}</p>
                                <div className="buttons">
                                    <button onClick={this.props.logoutUser} className="button is-danger">Logout</button>
                                </div>
                            </div>
                        </div>
                    }
                </div>
            </nav>
        )
    }
}

Navbar.propTypes = {
    logoutUser: PropTypes.func.isRequired,
    auth: PropTypes.object.isRequired
}

const mapStateToProps = state => ({
    auth: state.auth
})

export default connect(mapStateToProps, { logoutUser })(Navbar);

authAction.js

import { GET_ERRORS, SET_CURRENT_USER } from './types';
import axios from 'axios';
import setAuthToken from '../utils/setAuthToken';
import jwt_decode from 'jwt-decode';

export const loginUser = (userData) => dispatch => {
    axios.post('/api/users/login', userData)
        .then(res => {
            // Save to localStorage 
            const { token } = res.data;
            // Set token to lS
            localStorage.setItem('jwtToken', token);
            // Set token to Auth header
            setAuthToken(token);

            const decoded = jwt_decode(token);
            dispatch(setCurrentUser(decoded));
        })
        .catch(err => {
            dispatch({
                type: GET_ERRORS,
                payload: err.response.data
            });
        });
}

export const setCurrentUser = decoded => {
    return {
        type: SET_CURRENT_USER,
        payload: decoded
    }
}

export const logoutUser = () => dispatch => {
    localStorage.removeItem('jwtToken');
    setAuthToken(false);
    dispatch(setCurrentUser({}));
}

authReducer.js

import { SET_CURRENT_USER } from '../../actions/types';
import isEmpty from '../../validation/isEmpty';

const initialState = {
    isAuthenticated: false,
    user: {}
}

export default function (state = initialState, action) {
    const { type, payload } = action;

    switch (type) {
        case SET_CURRENT_USER:
            return {
                ...state,
                isAuthenticated: !isEmpty(payload),
                user: payload
            }
        default:
            return state;
    }
}

编辑:

护照配置

let JwtStrategy = require('passport-jwt').Strategy,
    ExtractJwt = require('passport-jwt').ExtractJwt,
    secret = require('../config/keys'),
    User = require('../models/Admin/Admin');

let opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = secret.secret;

module.exports = passport => {
    passport.use(new JwtStrategy(opts, (jwt_payload, done) => {
        User.findById(jwt_payload.id)
            .then(user => {
                if (user) {
                    return done(null, user);
                }
                return done(null, false);
            })
            .catch(err => {
                console.log(err);
            });
    }));
};

adminsReducer(等于用户):

import { GET_ADMINS, GET_ADMIN, EDIT_ADMIN } from '../../actions/types';

const initialState = {
    admins: [],
    admin: null
};

export default function (state = initialState, action) {
    const { type, payload } = action;

    switch (type) {
        case GET_ADMINS:
            return {
                ...state,
                admins: payload
            }
        case GET_ADMIN:
            return {
                ...state,
                admin: payload
            }
        case EDIT_ADMIN:
            return {
                ...state,
                admin: payload
            }
        default:
            return state;
    }
}

adminsAction:

import axios from 'axios';
import { GET_ADMINS, GET_ERRORS, GET_ADMIN, EDIT_ADMIN } from './types';


export const editAdmin = (name, editData, history) => dispatch => {
    axios.post(`/api/admins/edit/${name}`, editData)
        .then(res => {
            dispatch({type: EDIT_ADMIN, payload: res.data});
            history.push('/');
        })
        .catch(err => dispatch({
            type: GET_ERRORS,
            payload: err.response
        }))
}

1 个答案:

答案 0 :(得分:0)

您需要在编辑用户数据后在服务器端重新生成令牌,然后在响应中将其传递给客户端:

Admin.findOneAndUpdate(
  { _id: admin.id },
  { $set: updateAdmin },
  { new: true, useFindAndModify: false }
)
  .then(admin => {
    // generateJWT is a function you should replace with the one you are
    // actually using to generate a token
    const token = generateJWT(admin)
    return res.json({ admin, token })
  })
  .catch(err => res.json({ errors: err }))

然后存储JWT并从adminsAction.js中分发setCurrentUser(decoded),例如:

import axios from 'axios'
import { setCurrentUser } from './authAction'
import setAuthToken from '../utils/setAuthToken'
import { GET_ADMINS, GET_ERRORS, GET_ADMIN, EDIT_ADMIN } from './types'

export const editAdmin = (name, editData, history) => dispatch => {
  axios.post(`/api/admins/edit/${name}`, editData)
    .then(res => {
      dispatch({ type: EDIT_ADMIN, payload: res.data.admin })

      // Save to localStorage
      localStorage.setItem('jwtToken', res.data.token)
      // Set token to Auth header
      setAuthToken(res.data.token)
      // Set to Redux state
      dispatch(setCurrentUser(res.data.admin))

      history.push('/')
    })
    .catch(err => dispatch({
      type: GET_ERRORS,
      payload: err.response
    }))
}