关于 nodejs 里面的 jwt

关于token

为什么要用token?

对于传统的session,客户端做一次记录,以方便用户下次请求的鉴别,通常而言session都是保存在内存中,而随着认证用户的增多,服务端的开销会明显增大。

传统session存储的扩展性差,服务端做认证记录,如果认证的记录被保存在内存中的话,这意味着用户下次请求还必须要请求在这台服务器上,这样才能拿到授权的资源,这样在分布式的应用上,相应的限制了负载均衡器的能力。这也意味着限制了应用的扩展能力。

传统session的安全性差, cookie如果被截获,用户就会很容易受到跨站请求伪造的攻击(csrf)

token

基于token的鉴权机制类似于http协议是无状态的,它不需要在服务端去保留用户的认证信息或者会话信息。这就意味着基于token认证机制的应用不需要去考虑用户在哪一台服务器登录了,这就为应用的扩展提供了便利。

流程上是这样的:

  • 用户使用用户名密码来请求服务器

  • 服务器进行验证用户的信息

  • 服务器通过验证发送给用户一个token

  • 客户端存储token,并在每次请求时附送上这个token值

  • 服务端验证token值,并返回数据

这个token必须要在每次请求时传递给服务端,它应该保存在请求头里, 另外,服务端要支持CORS(跨来源资源共享)策略,一般我们在服务端这么做就可以了Access-Control-Allow-Origin: *

一个token由三部分组成。

第一部分我们称它为头部(header),第二部分我们称其为载荷(payload, 类似于飞机上承载的物品),第三部分是签证(signature).

Express中jwt的定义方式:

在用户验证的文件中,颁发jwt,设定规则,私钥和有效期:jwt规定token前要加Bearer标注
const rule = {
   id: user.id,
   email: user.email,
   name: user.name
};
const key = keys.secretOrKey;
jwt.sign(rule,key,{expiresIn: 3600},(err,token)=>{
           res.json({
               success: true,
               token: "Bearer " + token
          })
      }).catch(err => {
           return err;
      });
验证jwt

服务器文件中初始化passport,并将其作为参数传入passport的配置目录

const passport = require("passport");
// 初始化passport
app.use(passport.initialize());
// 把passport传入passport文件
require("./config/passport")(passport);
在passport的配置文件中配置token验证的方式为jwt验证
const JwtStrategy = require("passport-jwt").Strategy,
 ExtractJwt = require("passport-jwt").ExtractJwt;
// 读取数据库以便后面验证是否有相应userid对应的token  
const mongoose = require("mongoose");
const User = mongoose.model("users");
const keys = require("../config/keys");
const opts = {};

// 配置passport支持jwt
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = keys.secretOrKey;

// 导出passport-jwt
module.exports = (passport) => {
 passport.use(
   new JwtStrategy(opts, (jwt_payload, done) => {
     // 查看是否有该id生成的jwt  
     User.findOne({_id: jwt_payload.id}, (err, user) => {
       if (err) {
         return done(err, false);
      }
       if (user) {
         return done(null, user);
      } else {
         return done(null, false);
         // or you could create a new account
      }
    });
  })
);
};
在用户管理文件中引入配置好的passport
// 检测登录状态
// $route GET api/users/current
// @desc 返回当前登录的用户
// @access private
// 地址 验证token 回调函数
router.get("/current",passport.authenticate('jwt',{session:false}),
(req,res)=>{
 res.json({
   id: req.user.id,
   email: req.user.email,
   name: req.user.name
});
});

 

posted @ 2021-01-22 19:14  SvenWayne  阅读(396)  评论(0)    收藏  举报