天天看點

Node項目中使用jsonwebtoken實作JWT認證

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;
           

在控制台列印的結果為如下圖所示:

Node項目中使用jsonwebtoken實作JWT認證

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):編号

繼續閱讀