站長資訊網
        最全最豐富的資訊網站

        JWT是什么?Node中怎么實現JWT鑒權機制(淺析)

        本篇文章帶大家聊聊關于后端JWT鑒權的相關原理和如何在Node中去使用,希望對大家有所幫助,謝謝。

        JWT是什么?Node中怎么實現JWT鑒權機制(淺析)

        node.js極速入門課程:進入學習

        【相關教程推薦:nodejs視頻教程】

        一、為什么使用JWT

        一種技術的出現,就是彌補另一種技術的的缺陷。在JWT出現之前,Session 認證機制需要配合 Cookie 才能實現。由于 Cookie 默認不支持跨域訪問,所以,當涉及到前端跨域請求后端接口的時候,需要做很多額外的配置,才能實現跨域 Session 認證。

        注意:

        • 當前端請求后端接口不存在跨域問題的時候,推薦使用 Session 身份認證機制。
        • 當前端需要跨域請求后端接口的時候,不推薦使用 Session 身份認證機制,推薦使用 JWT 認證機制

        二、JWT是什么

        JWT(英文全稱:JSON Web Token)是目前最流行的跨域認證解決方案。本質就是一個字符串書寫規范,如下圖,作用是用來在用戶和服務器之間傳遞安全可靠的信息

        JWT是什么?Node中怎么實現JWT鑒權機制(淺析)

        在目前前后端分離的開發過程中,使用token鑒權機制用于身份驗證是最常見的方案,流程如下:

        • 服務器當驗證用戶賬號和密碼正確的時候,給用戶頒發一個令牌,這個令牌作為后續用戶訪問一些接口的憑證
        • 后續訪問會根據這個令牌判斷用戶是否有權限進行訪問

        三、JWT工作原理

        JWT是什么?Node中怎么實現JWT鑒權機制(淺析)

        總結:用戶的信息通過 Token 字符串的形式,保存在客戶端瀏覽器中。服務器通過還原 Token 字符串的形式來認證用戶的身份。

        四、token的組成部分

        Token,分成了三部分,頭部(Header)、載荷(Payload)、簽名(Signature),并以.進行拼接。其中頭部和載荷都是以JSON格式存放數據,只是進行了編碼。格式如下:

        Header.Payload.Signature
        登錄后復制

        下面是 JWT 字符串的示例:

        Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNjQ0ODI3NzI2LCJleHAiOjE2NDQ4Mjc3NTZ9.gdZKg9LkPiQZIgNAZ1Mn14GQd9kZZua-_unwHQoRsKE
        登錄后復制

        注意:Bearer 是手動添加的頭部信息,必須攜帶此信息才能解析token !

        五、token的三個部分的含義

        1. header

        每個JWT都會帶有頭部信息,這里主要聲明使用的算法。聲明算法的字段名為alg,同時還有一個typ的字段,默認JWT即可。以下示例中算法為HS256:

        { "alg": "HS256", "typ": "JWT" }
        登錄后復制

        因為JWT是字符串,所以我們還需要對以上內容進行Base64編碼,編碼后字符串如下:

        eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
        登錄后復制

        2. payload

        載荷即消息體,這里會存放實際的內容,也就是Token的數據聲明,例如用戶的idname,默認情況下也會攜帶令牌的簽發時間iat,通過還可以設置過期時間,如下:

        {     "sub": "1234567890",     "name": "CoderBin",     "iat": 1516239022 }
        登錄后復制

        同樣進行Base64編碼后,字符串如下:

        eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
        登錄后復制

        3. Signature

        簽名是對頭部和載荷內容進行簽名,一般情況,設置一個secretKey,對前兩個的結果進行HMACSHA25算法,公式如下:

        Signature = HMACSHA256(base64Url(header)+.+base64Url(payload),secretKey)
        登錄后復制

        一旦前面兩部分數據被篡改,只要服務器加密用的密鑰沒有泄露,得到的簽名肯定和之前的簽名不一致

        六、JWT使用方式

        客戶端收到服務器返回的 JWT 之后,通常會將它儲存在 localStoragesessionStorage 中。

        此后,客戶端每次與服務器通信,都要帶上這個 JWT 的字符串,從而進行身份認證。推薦的做法是把 JWT 放在 HTTP 請求頭的 Authorization 字段中,格式如下:

        Authorization: Bearer <token>
        登錄后復制

        七、JWT實現

        Token 的使用分成了兩部分:

        • 生成token:登錄成功的時候,頒發token
        • 驗證token:訪問某些資源或者接口時,驗證token

        接下來就在 node+express 環境下帶大家實現jwt鑒權,最后有完整代碼加注釋,可以直接看最后的代碼

        1. 安裝 JWT 相關的包

        運行如下命令,安裝如下兩個 JWT 相關的包:

        npm i jsonwebtoken express-jwt
        登錄后復制

        其中:

        • jsonwebtoken 用于生成 JWT 字符串
        • express-jwt 用于驗證token,將 JWT 字符串解析還原成 JSON 對象

        2. 導入 JWT 相關的包

        app.js

        // 導入用于生成 JWT 字符串的包 const jwt = require('jsonwebtoken')  // 導入用戶將客戶端發送過來的 JWT 字符串,解析還原成 JSON 對象的包 const expressJWT = require('express-jwt')
        登錄后復制

        3. 定義 secret 密鑰 *

        為了保證 JWT 字符串的安全性,防止 JWT 字符串在網絡傳輸過程中被別人破解,我們需要專門定義一個用于加密解密的 secret 密鑰:

        • 當生成 JWT 字符串的時候,需要使用 secret 密鑰對用戶的信息進行加密,最終得到加密好的 JWT 字符串

        • 當把 JWT 字符串解析還原成 JSON 對象的時候,需要使用 secret 密鑰進行解密

        // 這個 secretKey 的是可以是任意的字符串 const secretKey = 'CoderBin ^_^'
        登錄后復制

        4. 在登錄成功后生成 JWT 字符串 *

        調用 jsonwebtoken 包提供的 sign() 方法,將用戶的信息加密成 JWT 字符串,響應給客戶端:

        • 參數 1:用戶的信息對象
        • 參數 2:解密的秘鑰
        • 參數 3:配置對象,可以配置 token 的有效期

        注意:千萬不要把密碼加密到 token 字符串中!

        // 登錄接口 app.post('/api/login', function (req, res) {   // 將 req.body 請求體中的數據,轉存為 userinfo 常量   const userinfo = req.body   // 省略登錄失敗情況下的代碼...     // 登錄成功   // 在登錄成功之后,調用 jwt.sign() 方法生成 JWT 字符串。并通過 token 屬性發送給客戶端   const tokenStr = jwt.sign(     { username: userinfo.username },      secretKey,      { expiresIn: '30s' }   )      // 向客戶端響應成功的消息   res.send({     status: 200,     message: '登錄成功!',     token: tokenStr // 要發送給客戶端的 token 字符串   }) })
        登錄后復制

        5. 將 JWT 字符串還原為 JSON 對象 *

        客戶端每次在訪問那些有權限接口的時候,都需要主動通過請求頭中的 Authorization 字段,將 Token 字符串發送到服務器進行身份認證。

        此時,服務器可以通過 express-jwt 這個中間件,自動將客戶端發送過來的 Token 解析還原成 JSON 對象:

        • express.JWT({ secret: secretKey, algorithms: ['HS256'] }) 就是用來解析 Token 的中間件
        • express-jwt 模塊,現在默認為 6版本以上,必須加上: algorithms: ['HS256']

        注意:只要配置成功了 express-jwt 這個中間件,就會自動把解析出來的用戶信息,掛載到 req.user 屬性上

        // 1. 使用 app.use() 來注冊中間件 app.use(expressJWT({    secret: secretKey,    algorithms: ['HS256']  }).unless({ path: [/^/api//] }))
        登錄后復制

        注意

        • secret 必須和 sign 時候保持一致
        • 可以通過 unless 配置接口白名單,也就是哪些 URL 可以不用經過校驗,像登陸/注冊都可以不用校驗
        • 校驗的中間件需要放在需要校驗的路由前面,無法對前面的 URL 進行校驗

        6. 使用 req.user 獲取用戶信息

        當 express-jwt 這個中間件配置成功之后,即可在那些有權限的接口中,使用 req.user 對象,來訪問從 JWT 字符串中解析出來的用戶信息了,示例代碼如下:

        // 這是一個有權限的 API 接口,必須在 Header 中攜帶 Authorization 字段,值為 token,才允許訪問 app.get('/admin/getinfo', function (req, res) {   // TODO_05:使用 req.user 獲取用戶信息,并使用 data 屬性將用戶信息發送給客戶端   console.log(req.user);   res.send({     status: 200,     message: '獲取用戶信息成功!',     data: req.user // 要發送給客戶端的用戶信息   }) })
        登錄后復制

        7. 捕獲解析 JWT 失敗后產生的錯誤

        當使用 express-jwt 解析 Token 字符串時,如果客戶端發送過來的 Token 字符串過期或不合法,會產生一個解析失敗的錯誤,影響項目的正常運行。我們可以通過 Express 的錯誤中間件,捕獲這個錯誤并進行相關的處理,示例代碼如下:

        app.use((err, req, res, next) => {   // 這次錯誤是由 token 解析失敗導致的   if (err.name === 'UnauthorizedError') {     return res.send({       status: 401,       message: '無效的token'     })   }   res.send({     status: 500,     message: '未知的錯誤'   }) })
        登錄后復制

        8. 完整代碼

        app.js

        // 導入 express 模塊 const express = require('express') // 創建 express 的服務器實例 const app = express()  // TODO_01:安裝并導入 JWT 相關的兩個包,分別是 jsonwebtoken 和 express-jwt const jwt = require('jsonwebtoken') const expressJWT = require('express-jwt')   // 允許跨域資源共享 const cors = require('cors') app.use(cors())  // 解析 post 表單數據的中間件 const bodyParser = require('body-parser') // 這里用內置的中間件也行: app.use(express.urlencoded({ extended: false })) app.use(bodyParser.urlencoded({ extended: false }))  // TODO_02:定義 secret 密鑰,建議將密鑰命名為 secretKey // 這個 secretKey 的是可以是任意的字符串 const secretKey = 'smiling ^_^'  // TODO_04:注冊將 JWT 字符串解析還原成 JSON 對象的中間件 // 1. 使用 app.use() 來注冊中間件 // 2. express.JWT({ secret: secretKey, algorithms: ['HS256'] }) 就是用來解析 Token 的中間件 // 2.1 express-jwt 模塊,現在默認為 6版本以上,必須加上: algorithms: ['HS256'] // 3. .unless({ path: [/^/api//] }) 用來指定哪些接口不需要訪問權限 // 4. 注意:只要配置成功了 express-jwt 這個中間件,就會自動把解析出來的用戶信息,掛載到 req.user 屬性上 app.use(expressJWT({ secret: secretKey, algorithms: ['HS256'] }).unless({ path: [/^/api//] }))  // 登錄接口 app.post('/api/login', function (req, res) {   // 將 req.body 請求體中的數據,轉存為 userinfo 常量   const userinfo = req.body   // 登錄失敗   if (userinfo.username !== 'admin' || userinfo.password !== '000000') {     return res.send({       status: 400,       message: '登錄失敗!'     })   }   // 登錄成功   // TODO_03:在登錄成功之后,調用 jwt.sign() 方法生成 JWT 字符串。并通過 token 屬性發送給客戶端   // 參數 1:用戶的信息對象   // 參數 2:解密的秘鑰   // 參數 3:配置對象,可以配置 token 的有效期   // 記住:千萬不要把密碼加密到 token 字符串中!   const tokenStr = jwt.sign({ username: userinfo.username }, secretKey, { expiresIn: '30s' })   res.send({     status: 200,     message: '登錄成功!',     token: tokenStr // 要發送給客戶端的 token 字符串   }) })  // 這是一個有權限的 API 接口,必須在 Header 中攜帶 Authorization 字段,值為 token,才允許訪問 app.get('/admin/getinfo', function (req, res) {   // TODO_05:使用 req.user 獲取用戶信息,并使用 data 屬性將用戶信息發送給客戶端   console.log(req.user);   res.send({     status: 200,     message: '獲取用戶信息成功!',     data: req.user // 要發送給客戶端的用戶信息   }) })  // TODO_06:使用全局錯誤處理中間件,捕獲解析 JWT 失敗后產生的錯誤 app.use((err, req, res, next) => {   // 這次錯誤是由 token 解析失敗導致的   if (err.name === 'UnauthorizedError') {     return res.send({       status: 401,       message: '無效的token'     })   }   res.send({     status: 500,     message: '未知的錯誤'   }) })  // 調用 app.listen 方法,指定端口號并啟動web服務器 app.listen(8888, function () {   console.log('Express server running at http://127.0.0.1:8888') })
        登錄后復制

        八. 測試結果

        1 測試登錄接口

        借助 postman 工具測試接口

        JWT是什么?Node中怎么實現JWT鑒權機制(淺析)

        2. 測試登錄需要權限的接口-失敗

        JWT是什么?Node中怎么實現JWT鑒權機制(淺析)

        3. 測試登錄需要權限的接口-成功

        JWT是什么?Node中怎么實現JWT鑒權機制(淺析)

        九、最后總結

        JWT鑒權機制有許多優點:

        • json具有通用性,所以可以跨語言
        • 組成簡單,字節占用小,便于傳輸
        • 服務端無需保存會話信息,很容易進行水平擴展
        • 一處生成,多處使用,可以在分布式系統中,解決單點登錄問題
        • 可防護CSRF攻擊

        當然,不可避免的也有一些缺點:

        • payload部分僅僅是進行簡單編碼,所以只能用于存儲邏輯必需的非敏感信息
        • 需要保護好加密密鑰,一旦泄露后果不堪設想
        • 為避免token被劫持,最好使用https協議

        本次的淺析JWT鑒權機制就講到這里,希望對大家有所幫助,謝謝!

        贊(0)
        分享到: 更多 (0)
        網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
        主站蜘蛛池模板: 最新国产精品拍自在线播放| 精品999久久久久久中文字幕 | 精品久久久久久久无码| 国产精品无码永久免费888| 国产精品国产三级国产普通话| 亚洲精品成人a在线观看| 国产精品无码无卡无需播放器| 欧美极品欧美精品欧美视频| 精品国产第一国产综合精品| 自拍偷在线精品自拍偷| 日韩精品人成在线播放| 久久99精品久久久久久噜噜 | 99久久精品免费看国产免费| 国产精品爽爽va在线观看网站| 国产乱码精品一品二品 | 欧美日韩综合精品| 精品欧美一区二区在线看片| 国产精品女同一区二区久久| 在线精品视频播放| 911亚洲精品不卡| 一区二区三区国产精品| 热99re久久国超精品首页| 国产精品美女久久久久网| 2021国产精品视频| 92国产精品午夜福利| 成人午夜视频精品一区| 国产午夜无码精品免费看| 精品国偷自产在线| 国产欧美精品一区二区三区| 一级香蕉精品视频在线播放| 国产精品久久久久久久久| 久久精品国产精品亚洲下载| 精品国产一区二区三区AV性色| 国产精品成人99久久久久91gav| 欧美精品一区二区精品久久| 777被窝午夜精品影院| 国产精品 一区 在线| 国内精品99亚洲免费高清| 久久久久亚洲精品天堂久久久久久 | 最新精品国偷自产在线| 亚洲国产成人一区二区精品区|