Passport JWT req.user 在我的一条路线中未定义

Posted

技术标签:

【中文标题】Passport JWT req.user 在我的一条路线中未定义【英文标题】:Passport JWT req.user is undefined in one of my routes 【发布时间】:2017-03-26 22:53:37 【问题描述】:

我在尝试使用我的 express 应用设置 JWT 时简直是一场噩梦!认为我现在已经大部分工作了,我有一个注册路由和登录路由都可以正常工作并生成有效令牌,并且我的“/用户”路由中有另一个路由,我用它来测试身份验证,这一切都很好。但是我有另一个包含“/api”路由的文件,这是身份验证实际上很重要的地方,并且我有一个类似的测试路由尝试访问 req.user(就像我在其他路由中所做的那样),但它看起来像 req.user 。用户未定义。通过一些调试,看起来用户在 req.account 中,这很奇怪,我不明白为什么它不在 req.user 中

我在 /config/passport.js 中定义我的 jwt 策略

'use strict';
const User = require('../models/user'),
      config = require('./main'),
      JwtStrategy = require('passport-jwt').Strategy,
      ExtractJwt = require('passport-jwt').ExtractJwt;

//exported to be used by passport in server set up
module.exports = function (passport) 
  const jwtOptions =   
    // Telling Passport to check authorization headers for JWT
    jwtFromRequest: ExtractJwt.fromAuthHeader(),
    // Telling Passport where to find the secret
    secretOrKey: config.secret
  ;

  const jwtLogin = new JwtStrategy(jwtOptions, function(payload, done) 
    User.findById(payload._id, function(err, user) 
      if (err)  return done(err, false); 

      if (user) 
        done(null, user);
       else 
        done(null, false);
      
    );
  );

  passport.use(jwtLogin);


passport 作为参数传递给它,然后在主 express 文件中初始化

这里是 /users 路由文件,这很好用。使用 Authorization 标头和“JWT”向 /users/isAuth 发送 GET 请求可以正常工作,并且我的用户名会发回给我

"use strict";
const   express = require('express'),
        router = express.Router(),
        jwt = require('jsonwebtoken'),
        User = require('../models/user'),
        config = require('../config/main'),
        passport = require ('passport');

function generateToken(user) 
    return jwt.sign(_id: user._id, config.secret, 
        expiresIn: 10080
    );

.
. Here are routes for login and register they perform as expected
. and work fine
.
/*  ==================================
       Test Authentication Route
    ================================== */
router.get('/isAuth', passport.authenticate('jwt',  session: false ), function(req, res) 
    console.log(req.user);
    res.json(username: req.user.username);
);



module.exports = router;

但是,在这个文件中,对于发送请求到 GET /api/testAuth 的 api 路由,使用相同的令牌和相同的标头完全相同,我没有返回 req.user 并且在控制台中我看到了该 req。用户未定义。但是在控制台中似乎确实有用户对象,就像 req.account 一样?我不明白这里发生了什么希望有人能提供帮助!

"use strict";
const   express = require('express'),
        router = express.Router(),
        jwt = require('jsonwebtoken'),
        Server = require('../models/server'),
        passport = require('passport');

// Test route to see if logged in user is matt
router.get('/testAuth', passport.authorize('jwt',  session: false ), function(req, res) 
    console.log(req.user);
    if (req.user) 
        if(req.user.username == "matt") 
        res.send("You are matt!");
         else 
        res.send("You are not matt!");
        
     else 
        res.send("no req.user");
    

)

module.exports = router;

【问题讨论】:

Samson Maosa's answer 解决我的问题。 【参考方案1】:

req.user 对象仅在您使用使用会话的护照身份验证策略时设置。在这种情况下,身份验证是无状态的,因为您指定了session: false,这应该是 api 的方式。因此,会话没有用户对象。这是我在passport.authenticate 中间件中设置req.user 对象的方法:

    修改您的 jwtOptions 以启用将 req 对象传递给 JwtStrategy 函数:

    const jwtOptions =   
        // Telling Passport to check authorization headers for JWT
        jwtFromRequest: ExtractJwt.fromAuthHeader(),
        // Telling Passport where to find the secret
        secretOrKey: config.secret,
        passReqToCallback: true, //<= Important, so that the verify function can accept the req param ie verify(req,payload,done)
      ;
    

    修改 JwtStrategy 的参数,将请求对象作为第一个参数包含在内;然后在if (user) 块内,只需将返回的用户对象分配给req.user

    const jwtLogin = new JwtStrategy(jwtOptions, function(req, payload, done) 
        User.findById(payload._id, function(err, user) 
          if (err)  return done(err, false); 
    
          if (user) 
            req.user = user; // <= Add this line
            done(null, user);
           else 
            done(null, false);
          
        );
      );
    

就是这样:现在任何具有passport.authenticate("jwt", session: false) 中间件的路由都将在成功认证后收到req.user

【讨论】:

谢谢.. 好答案 => 节省了我的时间。 优秀的答案。保持我的代码干净并节省了我的时间。 根据文档,验证函数只接受两个参数,payloaddone。如果我添加 req 任何想法,我会收到错误消息? @ThéoChampion 看看第 1 步中的最后一个选项:passReqToCallback: true。请确保将其包含在 jwtOptions 中,然后您现在可以将 verify 称为 verify(req, payload, done)【参考方案2】:

您在您的 testAuth 路由中使用 passport.authorize,这适用于已经登录并拥有会话信息的用户。由于您没有使用会话存储,因此您没有持久的req.user 对象,因此应在所有路由上使用passport.authenticate

http://passportjs.org/docs/authorize

【讨论】:

这似乎是正确的答案,即使下面的答案被投票更多。您应该为您的每个请求发送Bearer token(WebSockets 除外),并在 Carlos 提到的所有路由上使用passport.authenticate('jwt', session: false

以上是关于Passport JWT req.user 在我的一条路线中未定义的主要内容,如果未能解决你的问题,请参考以下文章

在获取用户时使用 Passport-jwt 时 req.user 未定义

Passport JWT:req.user 始终未授权

可使用或不使用令牌 JWT+PASSPORT 的路线

Passport-jwt 不同的令牌相同的结果

PassportJS:如何在我的视图中获取 req.user

req.user 使用 passport.js 1-2 分钟后清除