Node.js 應用:Koa2 使用 JWT 進行鑑權
前言
在前後端分離的開發中,通過 Restful API 進行資料互動時,如果沒有對 API 進行保護,那麼別人就可以很容易地獲取並呼叫這些 API 進行操作。那麼伺服器端要如何進行鑑權呢?
Json Web Token 簡稱為 JWT,它定義了一種用於簡潔、自包含的用於通訊雙方之間以 JSON 物件的形式安全傳遞資訊的方法。JWT 可以使用 HMAC 演算法或者是 RSA 的公鑰金鑰對進行簽名。
說得好像跟真的一樣,那麼到底要怎麼進行認證呢?
首先使用者登入時,輸入使用者名稱和密碼後請求伺服器登入介面,伺服器驗證使用者名稱密碼正確後,生成token並返回給前端,前端儲存token,並在後面的請求中把token帶在請求頭中傳給伺服器,伺服器驗證token有效,返回正確資料。
既然伺服器端使用 Koa2 框架進行開發,除了要使用到 jsonwebtoken 庫之外,還要使用一個 koa-jwt 中介軟體,該中介軟體針對 Koa 對 jsonwebtoken 進行了封裝,使用起來更加方便。下面就來看看是如何使用的。
生成token
這裡註冊了個 /login
的路由,用於使用者登入時獲取token。
const router = require('koa-router')(); const jwt = require('jsonwebtoken'); const userModel = require('../models/userModel.js'); router.post('/login', async (ctx) => { const data = ctx.request.body; if(!data.name || !data.password){ return ctx.body = { code: '000002', data: null, msg: '引數不合法' } } const result = await userModel.findOne({ name: data.name, password: data.password }) if(result !== null){ const token = jwt.sign({ name: result.name, _id: result._id }, 'my_token', { expiresIn: '2h' }); return ctx.body = { code: '000001', data: token, msg: '登入成功' } }else{ return ctx.body = { code: '000002', data: null, msg: '使用者名稱或密碼錯誤' } } }); module.exports = router;
在驗證了使用者名稱密碼正確之後,呼叫 jsonwebtoken 的 sign() 方法來生成token,接收三個引數,第一個是載荷,用於編碼後儲存在 token 中的資料,也是驗證 token 後可以拿到的資料;第二個是金鑰,自己定義的,驗證的時候也是要相同的金鑰才能解碼;第三個是options,可以設定 token 的過期時間。
獲取token
接下來就是前端獲取 token,這裡是在 vue.js 中使用 axios 進行請求,請求成功之後拿到 token 儲存到 localStorage 中。這裡登入成功後,還把當前時間存了起來,除了判斷 token 是否存在之外,還可以再簡單的判斷一下當前 token 是否過期,如果過期,則跳登入頁面
submit(){
axios.post('/login', {
name: this.username,
password: this.password
}).then(res => {
if(res.code === '000001'){
localStorage.setItem('token', res.data);
localStorage.setItem('token_exp', new Date().getTime());
this.$router.push('/');
}else{
alert(res.msg);
}
})
}
然後請求伺服器端API的時候,把 token 帶在請求頭中傳給伺服器進行驗證。每次請求都要獲取 localStorage 中的 token,這樣很麻煩,這裡使用了 axios 的請求攔截器,對每次請求都進行了取 token 放到 headers 中的操作。
axios.interceptors.request.use(config => {
const token = localStorage.getItem('token');
config.headers.common['Authorization'] = 'Bearer ' + token;
return config;
})
驗證token
通過 koa-jwt 中介軟體來進行驗證,用法也非常簡單
const koa = require('koa');
const koajwt = require('koa-jwt');
const app = new koa();
// 錯誤處理
app.use((ctx, next) => {
return next().catch((err) => {
if(err.status === 401){
ctx.status = 401;
ctx.body = 'Protected resource, use Authorization header to get access\n';
}else{
throw err;
}
})
})
app.use(koajwt({
secret: 'my_token'
}).unless({
path: [/\/user\/login/]
}));
通過 app.use 來呼叫該中介軟體,並傳入金鑰 {secret: 'my_token'}
,unless 可以指定哪些 URL 不需要進行 token 驗證。token 驗證失敗的時候會丟擲401錯誤,因此需要新增錯誤處理,而且要放在 app.use(koajwt()) 之前,否則不執行。
如果請求時沒有token或者token過期,則會返回401。
解析koa-jwt
我們上面使用 jsonwebtoken 的 sign() 方法來生成 token 的,那麼 koa-jwt 做了些什麼幫我們來驗證 token。
resolvers/auth-header.js
module.exports = function resolveAuthorizationHeader(ctx, opts) {
if (!ctx.header || !ctx.header.authorization) {
return;
}
const parts = ctx.header.authorization.split(' ');
if (parts.length === 2) {
const scheme = parts[0];
const credentials = parts[1];
if (/^Bearer$/i.test(scheme)) {
return credentials;
}
}
if (!opts.passthrough) {
ctx.throw(401, 'Bad Authorization header format. Format is "Authorization: Bearer <token>"');
}
};
在 auth-header.js 中,判斷請求頭中是否帶了 authorization,如果有,將 token 從 authorization 中分離出來。如果沒有 authorization,則代表了客戶端沒有傳 token 到伺服器,這時候就丟擲 401 錯誤狀態。
verify.js
const jwt = require('jsonwebtoken');
module.exports = (...args) => {
return new Promise((resolve, reject) => {
jwt.verify(...args, (error, decoded) => {
error ? reject(error) : resolve(decoded);
});
});
};
在 verify.js 中,使用 jsonwebtoken 提供的 verify() 方法進行驗證返回結果。jsonwebtoken 的 sign() 方法來生成 token 的,而 verify() 方法則是用來認證和解析 token。如果 token 無效,則會在此方法被驗證出來。
index.js
const decodedToken = await verify(token, secret, opts);
if (isRevoked) {
const tokenRevoked = await isRevoked(ctx, decodedToken, token);
if (tokenRevoked) {
throw new Error('Token revoked');
}
}
ctx.state[key] = decodedToken; // 這裡的key = 'user'
if (tokenKey) {
ctx.state[tokenKey] = token;
}
在 index.js 中,呼叫 verify.js 的方法進行驗證並解析 token,拿到上面進行 sign() 的資料 {name: result.name, _id: result._id}
,並賦值給 ctx.state.user
,在控制器中便可以直接通過 ctx.state.user
拿到 name
和 _id
。
安全性
- 如果 JWT 的加密金鑰洩露的話,那麼就可以通過金鑰生成 token,隨意的請求 API 了。因此金鑰絕對不能存在前端程式碼中,不然很容易就能被找到。
- 在 HTTP 請求中,token 放在 header 中,中間者很容易可以通過抓包工具抓取到 header 裡的資料。而 HTTPS 即使能被抓包,但是它是加密傳輸的,所以也拿不到 token,就會相對安全了。
總結
這上面就是 jwt 基本的流程,這或許不是最完美的,但在大多數登入中使用已經足夠了。
上面的程式碼可能不夠具體,這裡使用 Koa + mongoose + vue.js 實現的一個例子 : jwt-demo,可以做為參考。
相關推薦
Node.js 應用:Koa2 使用 JWT 進行鑑權
前言 在前後端分離的開發中,通過 Restful API 進行資料互動時,如果沒有對 API 進行保護,那麼別人就可以很容易地獲取並呼叫這些 API 進行操作。那麼伺服器端要如何進行鑑權呢? Json Web Token 簡稱為 JWT,它定義了一種用於簡潔、自包含的用於
koa2服務端使用jwt進行鑑權及路由許可權分發
大體思路 後端書寫REST api時,有一些api是非常敏感的,比如獲取使用者個人資訊,檢視所有使用者列表,修改密碼等。如果不對這些api進行保護,那麼別人就可以很容易地獲取並呼叫這些 api 進行操作。 所以對於一些api,在呼叫之前,我們在服務端必須先對操作者進行“身份認證&rdq
自學Node.js 二:Node.js下的簡易web應用示例
var http = require("http"); var url = require("url"); var start = function(route,handle){ http.createServer(function(request,response)
node js實戰:帶數據庫,加密的註冊登錄表單
settings else input 是否 rip dig code setting 個人 demo 註冊效果: 登陸效果: 數據庫截圖: 數據庫操作 db.js //這個模塊裏面封裝了所有對數據庫的常用操作 var MongoClient =
模塊化方式構建Node.js應用程序
所有 改變 支持 don ash ogg 運行 xlsx 服務器 如今,幾乎所有的Web服務或集成都是在Node.js運行時上完成的。Node.js是一個具有很多社區支持的靈活平臺。我們甚至可以直接從Node.js創建xlsx,docx或pdf文檔。所有主流雲平臺都可以使用
PCB 第一個node.js應用
tex serve create 效果 run con 工作 resp UNC 一.Node安裝地址: https://nodejs.org/zh-cn/ 二.Node第一個應用實例 啟動webnode.js應用: node webnode.js
node js應用Redis初步
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
開發筆記13 | 部署 Node.js 應用程式到雲 ECS
<<系列文章集 前言 在之前的一篇文章中,我們介紹了 如何將一個本地的 Java 應用程式直接部署到阿里雲 ECS ,有不少讀者反饋,在本文中,我們來介紹如何部署 Node.js 應用程式到阿里雲 ECS。 本地開發 本文采用一個極其基礎的樣例《在 Web 頁面列印 HelloWorl
使用最基礎的Node,建立一個簡單的node.js應用
對於初學者 , 在我們使用 node.js建立應用時, 首先注意的應該是node.js的組成部分; 1:首先引入 require模組 可以使用require指令來載入node自己帶的node.js模組 ,方便引入;2: 2:建立伺服器: 伺服器可以監聽客戶端請求,從而響應資料
Node.js Streams:你需要知道的一切
Node.js Streams:你需要知道的一切 影象來源 Node.js流以難以使用而聞名,甚至更難理解。好吧,我有個好訊息 - 不再是這樣了。 多年來,開發人員在那裡建立了許多軟體包,其唯一目的是簡化流程。但在本文中,我將重點介紹本機Node.js流API。 “Str
如何建立高效能、可擴充套件的Node.js應用?
在這篇文章中,我們將介紹關於開發 Node.js web 應用程式的一些最佳實踐,重點關注效率和效能,以便用更少的資源獲得最佳結果。 提高 web 應用程式吞吐量的一種方法是對其進行擴充套件,多次例項化其以平衡在多個例項之間的傳入連線,接來下我們要介紹的是如何在多個核心上或多臺機器上對 Node
Node.js入門:模組機制
**CommonJS規範 ** 早在Netscape誕生不久後,JavaScript就一直在探索本地程式設計的路,Rhino是其代表產物。無奈那時服務端JavaScript走的路均是參考眾多伺服器端語言來實現的,在這樣的背景之下,一沒有特色,二沒有實用價值。但是隨著JavaScript在前端的應
使用 NestJS 開發 Node.js 應用
NestJS 最早在 2017.1 月立項,2017.5 釋出第一個正式版本,它是一個基於 Express,使用 TypeScript 開發的後端框架。設計之初,主要用來解決開發 Node.js 應用時的架構問題,靈感來源於 Angular。在本文中,我將粗略介紹 NestJS 中的一些亮點。 元件容器
node.js Web 框架Koa2
koa是Express的下一代基於Node.js的web框架,目前有1.x和2.0兩個版本。 歷史 1. Express Express是第一代最流行的web框架,它對Node.js的http進行了封裝,用起來如下: var express = require('expres
原始碼--Node.js 探祕:初識單執行緒的 Node.js
-- 高階理解 Nodejs, 從原始碼方向理解 // Node.js 探祕:初識單執行緒的 Node.js http://taobaofed.org/blog/2015/10/29/deep-into-node-1/ // 深入理解 Nod
蘇寧的Node.js實踐:不低於Java的渲染效能、安全穩定迭代快
前端 Node.js 的使用場景大多集中在前端工具上,當前的前端主要把它定位為輔助。蘇寧易購使用 Node.js 作為前後端分離的主要手段,經歷了從技術引進到全面開花,從邊緣功能到核心業務,從紛亂到穩定的過程。同時 Node.js 作為新引入的技術,與公司原有架構融合銜接面臨著怎樣的挑
最近學習的 Node.js 基礎:安裝、環境配置、forever
最近工作中,因為某某某某原因,需要用到Node.js 。 發現在很多方面和python很像,比如generator / yield ,比如模組的使用方式,比如http模組。 先安裝個環境,windows沒什麼難度,下載個安裝包裝一下就行,主要看一下centos的
Docker部署node.js應用
前言 什麼是docker? 通俗的理解,docker是建立和管理容器的一種技術。那什麼是容器呢?容器的功能與虛擬機器很近似,都是在一個物理主機上執行多個作業系統的技術。最大的不同之處在於,虛擬機器技術是虛擬出一套硬體後,在其上執行一個完整作業系統,在該系
Linux系統下 mongoDB + Node.js 應用搭建例項
· 0x01環境安裝首先使用WinSCP 連結Linux伺服器。①.Node找個資料夾,將node 專案放進去然後指令:1. 遠端下載node 8.9.4:wget https://npm.taobao.org/mirrors/node/v8.9.4/node-v8.9.4-
Node.js入門:前後端模組的異同
通常有一些模組可以同時適用於前後端,但是在瀏覽器端通過script標籤的載入JavaScript檔案的方式與Node.js不同。Node.js在載入到最終的執行中,進行了包裝,使得每個檔案中的變數天然的形成在一個閉包之中,不會汙染全域性變數。而瀏覽器端則通常是裸露的JavaScript程式碼片段。所以