Я работаю над проектом с использованием NodeJS, Express, React и Redux.
Я отображаю имя пользователя, вошедшего в систему в данный момент в системе навигации.
В настоящее время я кодирую обновление данных пользователя, но после редактирования данных имя пользователя не изменяется в панели навигации.
Я знаю, что это потому, что токен вошедшего в систему пользователя запоминает старые данные. Я использую PassportJWT. Как я могу обновить свои пользовательские данные в Passport после редактирования пользовательских данных (действие editAdmin
)?
Экспресс-маршрут обновления данных пользователя:
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
}))
}