使用node-jwt-simple的passport-local

92

如何将passport-local与成功认证返回JWT令牌相结合?

我想使用node-jwt-simple,但查看passport.js后,我不确定该如何进行操作。

var passport = require('passport')
  , LocalStrategy = require('passport-local').Strategy;

passport.use(new LocalStrategy(
  function(username, password, done) {
    User.findOne({ username: username }, function(err, user) {
      if (err) { return done(err); }
      if (!user) {
        return done(null, false, { message: 'Incorrect username.' });
      }
      if (!user.validPassword(password)) {
        return done(null, false, { message: 'Incorrect password.' });
      }
      return done(null, user);
    });
  }
));

在调用 done() 时是否可能返回令牌? 类似于这样的代码(仅为伪代码)

是否可能在调用 done() 时同时返回一个令牌?就像这个例子中的伪代码:

if(User.validCredentials(username, password)) {
  var token = jwt.encode({username: username}, tokenSecret);
  done(null, {token : token}); //is this possible?
}

如果不行,我该如何返回令牌?

3个回答

128

我想通了!

首先,您需要实现正确的策略。在我的情况下是 LocalStrategy,并且您需要提供您的验证逻辑。为了举例,让我们使用 passport-local 中的验证逻辑。

var passport = require('passport')
  , LocalStrategy = require('passport-local').Strategy;

passport.use(new LocalStrategy(
  function(username, password, done) {
    User.findOne({ username: username }, function(err, user) {
      if (err) { return done(err); }
      if (!user) {
        return done(null, false, { message: 'Incorrect username.' });
      }
      if (!user.validPassword(password)) {
        return done(null, false, { message: 'Incorrect password.' });
      }
      return done(null, user);
    });
  }
));

您提供的验证回调函数function(username, password, done)将负责查找用户并检查密码是否匹配(超出问题和我的回答范围)

passport.js需要几个要素才能正常工作,其中之一是在策略中返回用户。我试图更改代码的这部分,但是那样做是错误的。如果验证失败,则回调函数期望返回false,如果成功,则返回object(已验证的用户)。

现在....如何集成JWT?

在您的登录路由中,您将需要处理成功的身份验证或不成功的身份验证。在此处,您需要添加JWT令牌创建。如下所示:

(请记得禁用会话,否则您将不得不实现序列化和反序列化函数。如果您没有持久化会话,则无需这些函数,使用基于令牌的身份验证即可)

来自passport-local示例:(添加了JWT令牌)

// POST /login
//   This is an alternative implementation that uses a custom callback to
//   achieve the same functionality.
app.post('/login', function(req, res, next) {
  passport.authenticate('local', function(err, user, info) {
    if (err) { return next(err) }
    if (!user) {
      return res.json(401, { error: 'message' });
    }

    //user has authenticated correctly thus we create a JWT token 
    var token = jwt.encode({ username: 'somedata'}, tokenSecret);
    res.json({ token : token });

  })(req, res, next);
});

到此为止!现在当您调用 /login 并通过 SSL POST 用户名和密码时,第一个上面的代码片段将尝试根据您提供的用户名查找用户,然后检查密码是否匹配(当然,您需要更改以适应自己的需求)。

之后将调用您的登录路由,您可以在那里处理返回错误或有效令牌。

希望这会对某些人有所帮助。如果我有任何错误或遗漏,请让我知道。


4
护照(Passport)的BasicStrategy或DigestStrategy是另外两个选项。似乎Basic和Local策略之间没有太大区别,因为两者都不需要会话即可工作 - 只是Local要求提供重定向URL(使其稍微不那么API友好)。 - funseiki
2
嘿 @cgiacomi,你能给个检查令牌的路由示例吗? - Matt Kim
4
嘿@matt-kim,事实上我不保存token,它是短暂的。我不知道这是否是最好的方法,但这就是我的做法:用户进行身份验证,我生成token并返回给客户端。如果客户端是网站,则将token存储在localStorage中;如果是iPhone/Android应用,则可以将其存储在其中。当客户端必须请求资源时,它会将保存的token发送到后端。Passport将处理token。下面是使用Bearer策略处理token的代码片段:https://gist.github.com/cgiacomi/cd1efa187b8cccbe2a61希望这有所帮助! :) - cgiacomi
2
嘿@cgiacomi!也许这很明显,但您能描述一下在使用自定义回调时如何禁用会话吗? - MrMuh
3
@MrMuh,请查看链接https://gist.github.com/cgiacomi/cd1efa187b8cccbe2a61,在我的评论中,我展示了如何禁用会话:passport.authenticate('bearer', { session: false })。 - cgiacomi
显示剩余3条评论

20

这是一个很好的解决方案,我只想补充一点:

var expressJwt = require('express-jwt');

app.use('/api', expressJwt({secret: secret}));

我喜欢使用"express-jwt"来验证令牌。

顺便说一句:这篇文章很适合学习如何在客户端处理令牌,使用Angular,以便在每个请求中将其发送回去。

https://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/


3
我只使用express-jwt进行身份验证,但是阅读了其他包的文档,如passport-jwt,我认为我会坚持使用express-jwt。在我看来,它更简单,更好。 - bobbyz
仅供参考:express-jwt不支持刷新令牌。 - user3344977

4

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接