JSON Web Token
(JWT)是一個開放標準(RFC 7519),它定義了一種緊湊的、自包含的方式,用於做爲JSON
對象在各方之間安全地傳輸信息。該信息能夠被驗證和信任,由於它是數字簽名的。javascript
本文只講Koa2 + jwt
的使用,不瞭解JWT
的話請到這裏)進行了解。前端
要使用koa2+jwt
須要先有個koa
的空環境,搭環境比較麻煩,我直接使用koa起手式,這是我使用koa+typescript
搭建的空環境,若是你也常常用koa
寫寫小demo
,能夠點個star,方便~java
koa-jwt
主要做用是控制哪些路由須要jwt驗證,哪些接口不須要驗證:ios
import * as koaJwt from 'koa-jwt'; //路由權限控制 除了path裏的路徑不須要驗證token 其餘都要 app.use( koaJwt({ secret: secret.sign }).unless({ path: [/^\/login/, /^\/register/] }) );
上面代碼中,除了登陸、註冊接口不須要jwt驗證,其餘請求都須要。git
執行npm install jsonwebtoken
安裝jsonwebtoken
相關代碼:github
import * as jwt from 'jsonwebtoken'; const secret = 'my_app_secret'; const payload = {user_name:'Jack', id:3, email: '1234@gmail.com'}; const token = jwt.sign(payload, secret, { expiresIn: '1h' });
上面代碼中經過jwt.sign
來生成一個token,
參數意義:web
import * as crypto from 'crypto'; import * as jwt from 'jsonwebtoken'; async login(ctx){ //從數據庫中查找對應用戶 const user = await userRespository.findOne({ where: { name: user.name } }); //密碼加密 const psdMd5 = crypto .createHash('md5') .update(user.password) .digest('hex'); //比較密碼的md5值是否一致 若一致則生成token並返回給前端 if (user.password === psdMd5) { //生成token token = jwt.sign(user, secret, { expiresIn: '1h' }); //響應到前端 ctx.body = { token } } }
前端經過登陸拿到返回過來的token
,能夠將它存在localStorage
裏,而後再之後的請求中把token
放在請求頭的Authorization
裏帶給服務端。
這裏以axios
請求爲例,在發送請求時,經過請求攔截器把token
塞到header
裏:typescript
//請求攔截器 axios.interceptors.request.use(function(config) { //從localStorage裏取出token const token = localStorage.getItem('tokenName'); //把token塞入Authorization裏 config.headers.Authorization = `Bearer ${token}`; return config; }, function(error) { // Do something with request error return Promise.reject(error); } );
前端發送請求攜帶token,後端須要判斷如下幾點:數據庫
關於上面兩點,須要在後端寫一箇中間件來完成:npm
app.use((ctx, next) => { if (ctx.header && ctx.header.authorization) { const parts = ctx.header.authorization.split(' '); if (parts.length === 2) { //取出token const scheme = parts[0]; const token = parts[1]; if (/^Bearer$/i.test(scheme)) { try { //jwt.verify方法驗證token是否有效 jwt.verify(token, secret.sign, { complete: true }); } catch (error) { //token過時 生成新的token const newToken = getToken(user); //將新token放入Authorization中返回給前端 ctx.res.setHeader('Authorization', newToken); } } } } 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; }}); });
上面中間件是須要驗證token時都須要走這裏,能夠理解爲攔截器,在這個攔截器中處理判斷token是否正確及是否過時,並做出相應處理。
後端更換新token後,前端也須要獲取新token 這樣請求才不會報錯。
因爲後端更新的token是在響應頭裏,因此前端須要在響應攔截器中獲取新token。
依然以axios
爲例:
//響應攔截器 axios.interceptors.response.use(function(response) { //獲取更新的token const { authorization } = response.headers; //若是token存在則存在localStorage authorization && localStorage.setItem('tokenName', authorization); return response; }, function(error) { if (error.response) { const { status } = error.response; //若是401或405則到登陸頁 if (status == 401 || status == 405) { history.push('/login'); } } return Promise.reject(error); } );