飞道的博客

Node项目中使用jsonwebtoken实现JWT认证

358人阅读  评论(0)

1、需求说明

在前后端分离开发中,前端使用Vue.js框架,通过axios发送异步HTTP请求,服务端就无法使用session的方式保存用户的登录信息,因为客户端的每一次异步请求在服务端都会被认为是一个新的session。我们可以使用jwt(jsonwebtoken)的方式实现用户的校验。

2、安装相关依赖

服务端:
本文中使用Express作为服务端框架,需要在服务端安装以下JWT依赖:

cnpm i jsonwebtoken --save
cnpm i express-jwt --save

前端:
在前端使用Vue.js框架,需要安装axios用于发送HTTP请求:

cnpm i axios --save

3、代码实现

3.1、服务端代码

app.js入口文件引入 express-jwt ,示例代码如下:

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

var app = express();

app.use(expressJwt({
   
  credentialsRequired:false,
  secret: 'helloworld', //密钥
  algorithms: ['HS256'] //没有此配置项,在jwt6.0.0版本会报错:algorithms should be set
}).unless({
   
  path: ['/login'] //设置不需要token验证的路由 
}))

express-jwt 会自动验证请求头中的 token 信息。

在 routes/index.js 路由文件中创建用于登录和用户查询的路由,示例代码如下:

var express = require('express');
var router = express.Router();
var jwt = require('jsonwebtoken');

//用户登录的路由,此路由不会进行token校验
router.post('/login', function(req, res, next) {
   
  let {
   username,pwd} = req.body
  //模拟数据库查询账号密码
  if(username === 'admin' && pwd === '123456'){
   
  
    //生成Token信息jwt.sign(payload, secretOrPrivateKey, [options, callback])
    //payload参数为保存到客户端的用户信息,
    //secretOrPrivateKey 为密钥,要和 app.js 文件中的 secret 的值保持一致
    //option为配置项,expiresIn是token的有效时长,单位为秒,值也可以为字符串,例如 '2d' 表示2天
    
    let Token = jwt.sign({
   name: username,role: 1},'helloworld',{
   expiresIn: 60})
    
    res.json({
   
      code: 200,
      token: 'Bearer '+Token //向客户端响应的token前面必须添加 ’Bearer ’ 前缀
    })
    
  }else{
   
    res.json({
   
      code: 500
    })
  }
});

//查询用户信息的路由,此路由会校验token
router.get('/api/user/find', function(req,res,next){
   
  res.json({
   
    code: 200,
    result: ['tom','jack','lily']
  })
})

module.exports = router;

jwt.sign() 方法也可以使用异步加密的方式,示例代码如下:

//使用异步的方式生成token
jwt.sign(
	{
   name:username,role:1},
	'helloworld',
	{
   expiresIn:60},
	function(err,token){
   
      console.log(token)
    }
)

3.2、前端代码

views/Login.vue 用户登录组件,示例代码如下:

<template>
  <div>
      <input type="text" v-model="username" placeholder="用户名"></input>
      <input type="password" v-model="pwd" placeholder="密码"></input>
      <button @click="login">登录</button>
  </div>
</template>

<script>
import axiost from 'axios'
export default {
    
  data(){
    
    return {
    
      username: '',
      pwd: ''
    }
  },
  methods: {
    
    login(){
     //登录按钮点击事件
      axios.post("/login",{
    
		username: this.username,
		pwd: this.pwd
	  }).then(res=>{
    
		if(res.data.code === 200){
    
		    //保存token信息
			localStorage.token = res.data.token
		}
	  })
    }
  }
}
</script>

前端校验token的方法有以下几种:

(1)使用Vue的路由守卫校验

// 在路由全局前置守卫中判断 token 是否存在
router.beforeEach((to , from, next) => {
   
  // 获取 token
  if (localStorage.token)) {
   
    if (to.name === 'login') {
    // 如果用户在login页面
      next('/');
    } else {
   
      next();
    }
  } else {
   
   router.push('/login')
  }
});

(2)在axios请求拦截器中添加token信息

// axios请求拦截器
axios.interceptors.request.use(
  config => {
   
    if (localStorage.token) {
     // 判断是否存在token
      config.headers.authorization = localStorage.token;
    }
    return config;
  },
  err => {
   
    return Promise.reject(err);
  });

//axios响应拦截器
axios.interceptors.response.use(res => {
   
    return res;
  }, err=> {
   
    if (err.response.status === 401) {
    //token校验失败,没有访问权限
     //输出授权失败错误信息
    } else {
   
     //输出其他错误信息
    }
    return Promise.reject(err);
  }
);

也可以直接在 axios 实例函数中设置 headers ,示例代码如下:

let instance = axios.create({
   
    baseURL: 'http://localhost:3000',
    headers:{
   
       authorization: localStorage.getItem('token')
    }
})

instance.get('/xxx')

3.3、服务端校验token并获取用户信息

在服务端可以使用 express-jwt 自动完成校验,也可以手动完成校验,我们还可以在服务端获取保存到客户端的用户信息。在服务端的 routes/index.js 路由文件中编写一个用于token验证的测试路由,示例代码如下:

var express = require('express');
var router = express.Router();
var jwt = require('jsonwebtoken');

//用于验证token并获取用户信息
router.get('/yz', function(req,res,next){
   
  //从请求头中获取token内容
  let token = req.headers.authorization
  
  //由于token中包含 'Bearer '前缀,需要把前缀去掉获得token值
  token = token.replace('Bearer ','')
  
  let result = null;
  
  try{
   
  
    //jwt.verify(token,secretOrPublicKey,[options,callback]) 验证token的合法性
    // secretOrPublicKey 参数为密钥,要和生成token的密钥保持一致
    
    result = jwt.verify(token,'helloworld')
    console.log(result)
    
  }catch(err){
   
  
    console.error(err)
    
  }

  res.json({
   
    result
  })
})

module.exports = router;

在控制台打印的结果为如下图所示:

jwt.verify() 方法返回的值为 jwt.sign() 方法中的 payload 对象参数,JWT 规定了7个官方字段,供选用,分别是:

  • iss (issuer):签发人
  • exp (expiration time):过期时间
  • sub (subject):主题
  • aud (audience):受众
  • nbf (Not Before):生效时间
  • iat (Issued At):签发时间
  • jti (JWT ID):编号

转载:https://blog.csdn.net/p445098355/article/details/116211716
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场