前言
自己用react+koa實現了一個包含登陸和註冊功能的網址,在這裏記錄一下實現過程
項目地址:github地址
預覽地址:預覽地址
註冊
註冊其實沒什麼好說的,就是要注意不要明文保存密碼,否則數據庫泄露後,密碼會被其他人用來撞庫使用。
前臺加密主要是爲了防止post請求明文傳遞密碼,本來我想在前端加密,然後數據庫直接保存加密的密碼到數據庫,登陸時傳遞加密後的密碼進行登陸,但是前端使用的加密工具加密同一個密碼每次都生成不同的結果,導致每次查詢都是密碼不正確,我只能在後端先解密前端密碼,然後換用了一個加密工具,加密同一個密碼生成相同的結果,這樣查詢密碼纔會正確。
登陸
傳統的登錄系統是通過cookie
和session
做的登錄,這種登錄需要後端記錄session,當在線用戶很多時,會增加服務器壓力,這裏我使用JSON Web Token (JWT)
更好的方式來做登錄(後端不需要記錄任何東西)。關於cookie、session、token的概念我簡單的總結過,具體可以參考這裏
簡述登錄流程:
- 用戶使用賬號密碼登錄
- 後臺驗證賬號密碼是否正確,正確則生成
token
併發送給前臺。 - 前臺存儲
token
並在下次訪問傳遞給後臺 - 後臺驗證前臺傳過來的
token
是否正確,不正確則返回錯誤給前臺,讓他重新登錄
實際上我們需要解決以下問題就可以實現一個登陸:
- 後臺如何生成token?
- 前臺如何保存token,並傳遞給後臺?
- 既然後臺不保存任何信息,後臺如何驗證token?如何知道token不是僞造的
舉個簡單的例子:
我有個箱子要送出去,我自己不記錄我送了哪些箱子,別人送回來的時候我怎麼知道這是我的箱子?
很簡單,我給箱子上把鎖,別人還回來的時候,我用我自己的鑰匙打開,能打開就是我的箱子,否則就不是。
生成token時,我們可以將用戶名通過某種加密算法加密生成一個串字符串,解密時再用加密算法還原,如果可以還原就證明這個token有效,否則無效。
jsonwebtoken
我自己使用jsonwebtoken來生成和解析token,下面是一個簡單的使用
const jwt = require('jsonwebtoken');
const secert = 'secert_key' //相當於鑰匙,這個鑰匙不要讓其他人知道,否則別人會拿這個生成有效token
//加密,根據secert加密生成token
const token = jwt.sign({username:'zzh'},secert)
console.log('token',token)
//解密,如果token正確會還原,否則會拋出錯誤
try {
const result = jwt.verify(token,secert)
console.log(result)
} catch (error) {
console.log(error)
}
上面就是一個加密和解密的過程,這就實現token
的驗證。我們在登錄正確時,將用戶名或id用上面的方法加密生成token,並返回給前臺,前臺用某種方式存儲(SessionStorage、LocalStorage
),然後前端可以放在請求頭中傳遞給後臺,後臺再驗證token是否正確。
koa-jwt
直接使用上面的jsonwebtoken
太麻煩了,我們需要自己對接口進行token驗證和驗證失敗的處理。可以使用koa-jwt中間件來幫我們完成這些功能,我只需要會用即可。
//app.js
...
var jwt = require('koa-jwt');
app.use(jwt({ secret: 'secert_key' }).unless({ path: [/^\/public/] }));
當我們使用koa-jwt
中間件後,app會自動去驗證token,當token不存在或token失效時,會拋出401錯誤。另外我們要注意幾點:
- 生成token時還是用的
jsonwebtoken
進行加密的(koa-jwt自帶jsonwebtoken依賴) - 加密和解密的secret必須一樣(不要泄露)
koa-jwt
默認是從請求頭的Authorization中尋找token,如果需要以其他方式傳遞token則自行根據官網設置。Authorization:'Bearer ’ + token- 要設置不需要驗證token的接口,比如登陸接口是不需要驗證token的(通過unless設置)
關於koa-jwt
的使用可以看github文檔或這個demo
下面幾個問題可以思考
token存在前端什麼位置合適?
可以存在SessionStorage、LocalStorage、cookie中。
前端根據什麼判斷是否登錄?
當登陸成功時存儲token到cookie中,然後判斷cookie中是否有token
如何防止token被盜,然後繞過登陸的問題?
這樣有個問題,我可以通過瀏覽器的調試工具拿到token,然後在其他地方不登錄,在瀏覽器的調試工具手動設置token到cookie或storage中去,這樣就繞過了登錄。這其實是jwt的一個弊端,只要是一個正確的token,服務器都認爲是有效的。解決的方法可以用https或者將token有效時間縮短。
cookie的httpOnly只能防止前端讀取cookie,但是不能限制前端設置cookie
如何在退出登錄時使token失效?
可以將用過的token加入黑名單,這樣不管是退出登錄還是竊取別人的token使用都不會登錄成功
如何防止同個賬號同時登錄?