摘要:到這里,基于的前后端分離實現(xiàn)方案就搞定啦四關于的一些思考實際上,在使用的過程中有一個比較致命的缺點,就是一旦簽發(fā)了,在到期之前就會始終有效,除非服務器部署額外的邏輯。結語以上是關于基于的前后端分離實現(xiàn)方案的總結和思考。
一、jwt是什么
JWT全稱, JSON Web Token,是一個以JSON為基準的標準規(guī)范。
舉例:服務器認證以后,生成一個 JSON 對象,發(fā)回給用戶,就像下面這樣
{ "姓名": "brook", "角色": "前端攻城獅", "帥氣指數(shù)": "5顆星" }
以后,用戶與服務端通信的時候,都要發(fā)回這個 JSON 對象。服務器完全只靠這個對象認定用戶身份。為了防止用戶篡改數(shù)據(jù),服務器在生成這個對象的時候,會加上簽名(詳見后文)。
將上面的 JSON 對象使用 Base64URL 算法(詳見后文)轉成字符串。
我們先看看jwt的真實面目
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwibmFtZSI6ImFkbWluIiwidXNlcm5hbWUiOiJhZG1pbiIsInBvc2l0aW9uIjoiIiwicGhvbmUiOm51bGwsImVtYWlsIjpudWxsLCJyb2xlIjpbImFkbWluIl0sImF2YXRhciI6Imh0dHA6Ly9pbWcuZG9uZ3FpdWRpLmNvbS91cGxvYWRzL2F2YXRhci8yMDE1LzA3LzI1L1FNMzg3bmg3QXNfdGh1bWJfMTQzNzc5MDY3MjMxOC5qcGciLCJpbnRyb2R1Y3Rpb24iOiIiLCJjcmVhdGVfdGltZSI6IjIwMTctMTEtMDJUMTg6MTU6NDguMDAwWiIsInVwZGF0ZV90aW1lIjoiMjAxNy0xMS0yNlQwNjozMzoxNy4wMDBaIiwiaWF0IjoxNTM5MjQ0NjQ1fQ.cRg7ZAQ-1ZBiJUPDx6naQupUMK2BLHmIusMQZrnqVpG
它是一個很長的字符串,中間用點(.)分隔成三個部分。三個部分依次為
Header(頭部) Payload(負載) Signature(簽名)
即header.payload.sign。
Header 部分是一個 JSON 對象,描述 JWT 的元數(shù)據(jù)。
Payload 部分也是一個 JSON 對象,用來存放實際需要傳遞的數(shù)據(jù)。JWT 規(guī)定了7個官方字段,供選用。
Signature 部分是對前兩部分的簽名,防止數(shù)據(jù)篡改。
關于這三部分的詳解,可以具體參考阮一峰老師的文章:http://www.ruanyifeng.com/blo...
在使用jwt的時候建議放在 HTTP 請求的頭信息Authorization字段里面,如下
Authorization: Bearer二、jwt的好處
前后端分離:使用JWT作為接口鑒權不需要前端代碼發(fā)布到后端指定目錄下,可以完全跨域,前端項目可以多帶帶部署
減輕服務端內存負擔:比起使用session來保存cookie,JWT自身包含了所有信息,通過解密即可驗證(當然啦,這個通過吧session存在redis來避免)
安全性:防止CSRF攻擊
移動端:對于無法使用cookie的一些移動端,JWT能夠正常使用
部署:服務器不需要保存session數(shù)據(jù),無狀態(tài),容易擴展
PS:為什么不寫為什么使用jwt呢,因為它其實還是存在不少缺點的,需要根據(jù)使用業(yè)務場景確定,不是所有的場景都適合使用jwt,甚至網上有些帖子都是在評論jwt比較雞肋的。具體可以看分析
https://juejin.im/entry/59748...
直接上圖,流程如下
我們以Eggjs項目為例,使用koa-jwt這個庫
https://github.com/koajs/jwt
config.middleware = ["compress", "errorHandler","jwt"]; // 加上配置 config.jwt = { match: "/api", secret: "abiao", unless: ["/api/user/login"], };
match指egg路由匹配到相應前綴,則會使用當前的中間件。可以使用正則表達式去匹配,推薦api前綴定為api。
secret指jwt的加密密鑰。
unless指指定的路由不經過此中間件,一般為login接口
PS:egg中使用插件有全局模式和中間件模式。全局模式應該使用egg的插件,中間件模式可以使用第三方koa的插件
jwt.js
const jwt = require("koa-jwt"); module.exports = (options, app) => { let jwtMiddlerware = jwt( { secret: options.secret, } ); if (options.unless) { jwtMiddlerware = jwtMiddlerware.unless({path: options.unless}) } return jwtMiddlerware };
egg會自動往middleware的中間件里注入配置。在中間件里就可以使用koa-jwt對我們的接口進行保護
* login() { const params = this.ctx.request.body; const rule = { username: "string", password: "string" }; this.ctx.validate(rule, params); // 調用 service 進行業(yè)務處理 const res = yield this.service.user.login(params); // 獲取jwt的配置 let {jwt:jwtConf} = app.config; // 使用密鑰對用戶數(shù)據(jù)進行加密,生成jwt let token = jwt.sign(res,jwtConf.secret); res.token = token; this.ctx.body = this.ctx.helper.success(res); }前端
LoginByUsername({ commit }, userInfo) { const username = userInfo.username.trim() return new Promise((resolve, reject) => { loginByUsername(username, userInfo.password).then(response => { const data = response.data // 把jwt存儲到localStorage里 LocalStorage.setItem("token", data.payload.token) resolve(data) }).catch(error => { reject(error) }) }) }
PS:網上關于jwt應該存儲到哪里有一篇分析,推薦是存到cookie里,因為可以避免XSS攻擊,鏈接如下:
https://blog.csdn.net/loveyou...
經過實踐,假如在服務端把token寫入cookie,并設置為httpOnly,本地前端是獲取不到cookie里的token的,也就沒辦法在header里帶上token給后端校驗,不可行;所以token還是需要讓前端自己存儲,而前端把token存儲在cookie是沒辦法設置httpOnly的,所以規(guī)避不了XSS攻擊。不管是在放localStorage和cookie里都會遇到XSS的問題,這個只能通過對用戶輸入進行轉碼來防范;而放在localStorage里會比放在cookie里好,因為每次請求不會在cookie里又帶上token,減少了請求體的大小。
綜上所述,我認為token應該讓前端存儲在localStorage里,同時做好XSS防范。
推薦的做法是使用請求攔截器,推薦使用axios
import axios from "axios" // 創(chuàng)建axios實例 const service = axios.create({ baseURL: "/", timeout: 5000 }) // request攔截器 service.interceptors.request.use(config => { if (LocalStorage.getItem("token")) { config.headers["authorization"] = "Bearer " + LocalStorage.getItem("token") } return config }, error => { Promise.reject(error) })
寫完基本流程之后我們帶上jwt請求一個接口看看效果
返回結果正常。同時,我們也驗證一下沒有token的情況下。我們手動清除了cookie再請求一次接口
接口會返回unauthorizeError,這個是我們期待的返回結果。當然啦,我們也可以在后端catch這個錯誤,返回更加友好的信息,例如401,讓前端提示會話過期并自動跳轉到登錄頁。我們簡單演示這一步就先跳過了。
到這里,基于jwt的前后端分離實現(xiàn)方案就搞定啦!
四、關于jwt的一些思考實際上,jwt在使用的過程中有一個比較致命的缺點,就是一旦 JWT 簽發(fā)了,在到期之前就會始終有效,除非服務器部署額外的邏輯。這對于要臨時禁止某個用戶的操作,修改某個用戶權限并馬上生效的業(yè)務場景,是滿足不了的,而對于做得比較完善的業(yè)務系統(tǒng)來講都會有類似的需求,所以是否使用jwt,還需要謹慎評估。
JWT 的最佳用途是「一次性授權 Token」,這種場景下的 Token 的特性如下:
有效期短,只希望被使用一次。
例如分享一個文件給朋友,在指定1小時打開有效。
以上是關于基于jwt的前后端分離實現(xiàn)方案的總結和思考。此外分享一個accesstoken的方案,可以作為jwt的替代方案,詳情可以查看loopback框架的Authorization,可以滿足大部分的業(yè)務場景。
https://loopback.io/doc/en/lb...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/103958.html
摘要:進行下一項配置,為了區(qū)分必須加入。另起一行,以示尊重。這行代碼主要是用于驗證,后面再說。然后跑下接口,發(fā)現(xiàn)沒問題,正常打印,說明主體也在上下文中了。說明這會上下文環(huán)境中我們主體不存在。所說以,主體數(shù)據(jù)生命周期是一次請求。 showImg(https://segmentfault.com/img/bVbtoG1?w=1600&h=900); 原來一直使用shiro做安全框架,配置起來相當...
摘要:自己在前后端分離上的實踐要想實現(xiàn)完整的前后端分離,安全這塊是繞不開的,這個系統(tǒng)主要功能就是動態(tài)管理,這次實踐包含兩個模塊基于搭建的權限管理系統(tǒng)后臺編寫的前端管理。 自己在前后端分離上的實踐 要想實現(xiàn)完整的前后端分離,安全這塊是繞不開的,這個系統(tǒng)主要功能就是動態(tài)restful api管理,這次實踐包含兩個模塊,基于springBoot + shiro搭建的權限管理系統(tǒng)后臺bootshir...
摘要:自己在前后端分離上的實踐要想實現(xiàn)完整的前后端分離,安全這塊是繞不開的,這個系統(tǒng)主要功能就是動態(tài)管理,這次實踐包含兩個模塊基于搭建的權限管理系統(tǒng)后臺編寫的前端管理。 自己在前后端分離上的實踐 要想實現(xiàn)完整的前后端分離,安全這塊是繞不開的,這個系統(tǒng)主要功能就是動態(tài)restful api管理,這次實踐包含兩個模塊,基于springBoot + shiro搭建的權限管理系統(tǒng)后臺bootshir...
閱讀 3564·2023-04-26 00:05
閱讀 953·2021-11-11 16:55
閱讀 3522·2021-09-26 09:46
閱讀 3517·2019-08-30 15:56
閱讀 909·2019-08-30 15:55
閱讀 2933·2019-08-30 15:53
閱讀 1939·2019-08-29 17:11
閱讀 814·2019-08-29 16:52