如何使用标头中的用户 JWT 令牌转发授权并将其与 cookie 中的 JWT 令牌进行比较以验证用户?

Posted

技术标签:

【中文标题】如何使用标头中的用户 JWT 令牌转发授权并将其与 cookie 中的 JWT 令牌进行比较以验证用户?【英文标题】:How do I forward authorization with the user JWT token in the header and compare it to the JWT token in the cookie to Auth user? 【发布时间】:2021-12-07 06:10:01 【问题描述】:

我的登录用户有问题,当我刷新页面时,用户迷路了。这就是我分配 JWT 令牌的方式:

const signToken = id => 
  return jwt.sign( id , 'my-ultra-secure-and-ultra-long-secret', 
    expiresIn: '14d',
  );
;

这也是我使用此函数向 cookie 发送令牌的方式:

const createSendToken = (user, statusCode, res) => 
  const token = signToken(user._id);

  const cookieOptions = 
    expires: new Date(Date.now() + 14 * 1000 * 60 * 24),
    httpOnly: true,
  ;

  res.cookie('jwt', token, cookieOptions);

  // Remove password from output
  user.password = undefined;

  res.status(statusCode).json(
    status: 'success',
    token,
    data: 
      user,
    ,
  );
;

这是我的登录控制器:

exports.login = catchAsync(async (req, res, next) => 
  const  email, password  = req.body;

  // 1) Check if email and password exist
  if (!email || !password) 
    return next(new AppError('Please provide email and password!', 400));
  
  // 2) Check if user exists && password is correct
  const user = await User.findOne( email ).select('+password');

  if (user && (await user.correctPassword(password, user.password))) 
    createSendToken(user, 200, res);
   else 
    return next(new AppError('Incorrect email or password', 401));
  
);

这是我的 Protect 控制器(保护中间件):

exports.protect = catchAsync(async (req, res, next) =>

  // 1) Getting token and check of it's there
  let token;
  if (
    req.headers.authorization &&
    req.headers.authorization.startsWith('Bearer')
  ) 
    token = req.headers.authorization.split(' ')[1];
  
  if (!token) 
    return next(
      new AppError('You are not logged in! Please log in to get access.', 401)
    );
  
  // 2) Verification token
  const decoded = await promisify(jwt.verify)(
    token,
    'my-ultra-secure-and-ultra-long-secret'
  );
  // 3) Check if user still exists
  const currentUser = await User.findById(decoded.id);
  if (!currentUser) 
    return next(
      new AppError(
        'The user belonging to this token does no longer exist.',
        401
      )
    );
  
  // 4) Check if user changed password after the token was issued
  if (currentUser.changedPasswordAfter(decoded.iat)) 
    return next(
      new AppError('User recently changed password! Please log in again.', 401)
    );
  
  // GRANT ACCESS TO PROTECTED ROUTE
  req.user = currentUser;
  res.locals.user = currentUser;
  next();
);

这是我使用这个中间件的私有路由:

router.route('/:id').get(authController.isLoggedIn, postController.getPost);

问题是当我登录时我得到一个 cookie,但我无法访问受保护的路由(我得到一个错误令牌未定义)。当我刷新页面时,用户丢失了,但 cookie 仍在存储中。当我尝试通过邮递员访问保护路由并将授权承载添加到标题时.....(令牌)我可以访问它。

这是我的前端用户减速器:

export const userLoginReducer = (state = , action) => 
  switch (action.type) 
    case USER_LOGIN_REQUEST:
      return  loading: true, isAuthenticated: false ;
    case USER_LOGIN_SUCCESS:
      return 
        loading: false,
        isAuthenticated: true,
        user: action.payload,
      ;
    case USER_LOGIN_FAIL:
      return  loading: false, isAuthenticated: false, error: action.payload ;
    case USER_LOGOUT:
      return  loading: false, isAuthenticated: false, user: null ;
    default:
      return state;
  
;

这是我的用户操作:

export const login = (email, password) => async dispatch => 
  try 
    dispatch(
      type: USER_LOGIN_REQUEST,
    );

    const config = 
      headers: 
        'Content-Type': 'application/json',
      ,
    ;

    const  data  = await axios.post(
      '/api/v1/users/login',
       email, password ,
      config
    );

    dispatch(
      type: USER_LOGIN_SUCCESS,
      payload: data,
    );

   
   catch (error) 
    dispatch(
      type: USER_LOGIN_FAIL,
      payload:
        error.response && error.response.data.message
          ? error.response.data.message
          : error.message,
    );
  
;

这是我的登录屏幕:

  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');

  const redirect = location.search ? location.search.split('=')[1] : '/';

  const dispatch = useDispatch();

  const userLogin = useSelector(state => state.userLogin);
  const  loading, error, isAuthenticated  = userLogin;
  console.log(isAuthenticated);

  useEffect(() => 
    if (isAuthenticated) 
      history.push(redirect);
    

    if (error) 
      console.log(error);
    
  , [isAuthenticated, history, redirect, error]);

  const submitHandler = e => 
    e.preventDefault();
    dispatch(login(email, password));
  ;

我在这里停留了大约 2 天,试图完成这个。请有人帮助我:)

【问题讨论】:

【参考方案1】:

当您在 cookie 中设置 jwt 令牌时,您可以在发出请求时从那里读取它。您可以通过在您的 axios 配置对象中添加 withCredentials: true 来使用 axios 自动发送 cookie,例如:

axios(
 withCredentials: true
)

在服务器端,您可以通过查看req.cookies 对象来获取 jwt cookie 值,例如:

let token;
if (req.cookies.jwt) 
  token = req.cookies.jwt;

【讨论】:

我不知道为什么会这样,但它可以“让令牌;如果(req.cookies.jwt)令牌= req.cookies.jwt;”现在当我有cookie时,我可以访问受保护的路线,当我从存储中删除 cookie 或注销时,我不能。那很好。现在我想知道如何让用户保持登录状态。登录时我在标题中显示用户名,这没关系,但是当我刷新页面时,我的用户消失了并得到错误 user.name is undefind 要了解 cookie 的工作原理,您可以查看expressjs.com/en/resources/middleware/cookie-parser.html。对于刷新页面问题,我认为有另一条路线来检查用户会话,比如让控制器验证 jwt 令牌并将用户信息作为名称返回,而在前端你可以在等待时处于加载状态用于用户会话检查。如果您使用的是反应路由器,这可以帮助您reactrouter.com/web/example/auth-workflow 当我登录并刷新您发送给我的链接上的页面(右侧输出)时,同一用户丢失了

以上是关于如何使用标头中的用户 JWT 令牌转发授权并将其与 cookie 中的 JWT 令牌进行比较以验证用户?的主要内容,如果未能解决你的问题,请参考以下文章

如何模拟 JWT 令牌以将其与 Mockito 和 Spring Boot 一起使用

如何在授权标头中将带有 fetch 和 cors 的 JWT 令牌发送到 Express 服务器?

响应标头中缺少 jwt 授权令牌

JWT 令牌未在 $resource 中的标头上设置

护照-jwt 总是返回“未经授权” - 401

如何在所有请求标头中传递授权令牌 - Spring Boot java