關(guān)鍵詞:刷新JWT,更新,緩存
平臺(tái):數(shù)據(jù)庫(kù)(mongodb, mysql),redis
首先在用戶注冊(cè)的時(shí)候,我們需要收集用戶的賬號(hào)信息 譬如 id + username + 亂七八糟mix salt 的組合用md5加密成一串用戶初始token,和用戶信息一起存入數(shù)據(jù)庫(kù),作為用戶在平臺(tái)唯一識(shí)別token(注意這個(gè)token和jwt發(fā)的token不是一回事)。
在用戶注冊(cè)登錄的時(shí)候就把上述token作為cookie塞給用戶瀏覽器,存在redis維護(hù)一份(這里看策略,一般可能2-4小時(shí)后失效),redis保存信息形式大概為token:{用戶基本信息}
【下面的代碼僅為思路展示,像很多sql和redis操作不能直接套用,僅供參考】
async login(ctx, next) {
? try {
? const {username, pwd} = await Util.treamentFormData(ctx.req)
? const handlePsw = md5Pwd(pwd)
? const getCheckUserInfo = await query(
? `SELECT FROM users WHERE name = ${username} AND vkey = ${handlePsw}`
? )
? if (!getCheckUserInfo) {
? return ctx.body =({code: 1, msg: '用戶名或密碼錯(cuò)誤'})
? } else {
? const userInfo = {username: findOneRes.username, vkey: findOneRes.vkey}
? const token = Util.setToken(userInfo)
? const redis = initStone()
? redis.set(findOneRes.vkey, JSON.stringify(userInfo) , 'EX', 60 * 60 * 2) *//秒為單位 2個(gè)小時(shí)redis失效*
? const CookieOpt = CookieConfig()
? try {
? ctx.cookies.set('_token', findOneRes.vkey, CookieOpt)
? } catch(err) {
? console.log(err)
? }
? ctx.response.body = ({code: 0, data: {...findOneRes._doc, token}})
? }
? } catch (e) {
? ctx.response.body = e
? }
},
基于jwt有時(shí)效性我們前端調(diào)用的時(shí)候先查驗(yàn)一下jwt的有效時(shí)間,這里可以發(fā)起一個(gè)請(qǐng)求去獲取最新的jwt,使用cookie作為憑據(jù)(所以這個(gè)cookie的時(shí)間可以設(shè)長(zhǎng)一點(diǎn),比如一個(gè)月),然后使用全局變量維護(hù)這個(gè)拿下來(lái)的jwt,當(dāng)下一個(gè)接口請(qǐng)求的時(shí)候,會(huì)先去本地拿這個(gè)對(duì)象看看過(guò)沒(méi)過(guò)期,如果過(guò)期了,去調(diào)這個(gè)獲取jwt的接口再拿一次新的,這個(gè)接口返回新的token和用戶個(gè)人信息
*// 處理鑒權(quán) 不刷新cookie*
async accessToken(ctx, next) {
? try {
? const getCookie = ctx.request.header.cookie
? if (getCookie) {
? *// redis.set('DD', 100, 'EX', 5) //秒為單位*
? const parseCookie = Util.handleCookie(getCookie)
? const getCookieToken = parseCookie['_token']
? const redis = initStone()
? const result = await redis.get(`${getCookieToken}`)
? if (result) {
? const userInfo = JSON.parse(result)
? const newToken = Util.setToken(userInfo)
? ctx.body = ({code: 0, msg: 'success' , data: {token: newToken, userInfo}})
? } else {
? const getUserInfo = await query(
? `SELECT FROM users WHERE vkey = ${handlePsw}`
? )
? if (getUserInfo) {
? redis.set(getUserInfo.vkey, JSON.stringify(getUserInfo) , 'EX', 60 * 60 * 2) *//秒為單位 2個(gè)小時(shí)redis失效*
? const newToken = Util.setToken(getUserInfo)
? ctx.body = ({code: 0, msg: 'success' , data: {token: newToken, getUserInfo}})
? }
? }
? } else {
? ctx.status = 401
? ctx.body = ({code: -1, msg: 'fail'})
? }
? } catch(e) {
? console.log(e)
? }
}
這里通過(guò)cookie的toke去獲取用戶信息,如果redis上有這個(gè)信息(即_token = redis上的key "_token"),直接使用redis上的信息頒布新的jwt,如果沒(méi)有,則通過(guò)這個(gè)token我們可以去查詢數(shù)據(jù)里面?zhèn)€人信息,查到后再塞一次到redis,并且再返回個(gè)人信息和新的jwt給前端。
{
? account: {
? username: '',
token: ''
? …otherInfo,
? }
}