<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Java 后端實(shí)現(xiàn) token自動(dòng)續(xù)期,這方案有點(diǎn)優(yōu)雅!

          共 3606字,需瀏覽 8分鐘

           ·

          2021-11-04 21:48

          大家好,我是小富~

          在前后端分離的開(kāi)發(fā)模式下,前端用戶登錄成功后后端服務(wù)會(huì)給用戶頒發(fā)一個(gè)token。前端(如vue)在接收到 token后會(huì)將token存儲(chǔ)到LocalStorage中。

          后續(xù)每次請(qǐng)求都會(huì)將此token放在請(qǐng)求頭中傳遞到后端服務(wù),后端服務(wù)會(huì)有一個(gè)過(guò)濾器對(duì)token進(jìn)行攔截校驗(yàn),校驗(yàn)token的合法性以及token是否過(guò)期,如果token過(guò)期則會(huì)讓前端跳轉(zhuǎn)到登錄頁(yè)面重新登錄。

          因?yàn)閠oken中一般會(huì)包含用戶的基礎(chǔ)信息,為了保證token的安全性,一般會(huì)將token的過(guò)期時(shí)間設(shè)置的比較短。

          但是這樣又會(huì)導(dǎo)致前端用戶需要頻繁登錄(token過(guò)期),甚至有的表單比較復(fù)雜,前端用戶在填寫(xiě)表單時(shí)需要思考較長(zhǎng)時(shí)間,等真正提交表單時(shí)后端校驗(yàn)發(fā)現(xiàn)token過(guò)期失效了不得不跳轉(zhuǎn)到登錄頁(yè)面。重新登錄填寫(xiě)后再提交表單,用戶體驗(yàn)非常不友好。

          本篇文章的內(nèi)容就要是在前端用戶無(wú)感知的情況下實(shí)現(xiàn)token的自動(dòng)續(xù)期,避免頻繁登錄、表單填寫(xiě)內(nèi)容丟失情況的發(fā)生。當(dāng)然,這只是萬(wàn)千解決方案中的一種,如果你有更好的方案,歡迎留言評(píng)論。

          實(shí)現(xiàn)原理

          token自動(dòng)續(xù)期的實(shí)現(xiàn)原理如下:

          1. 登錄成功后將用戶生成的token 作為key、value存儲(chǔ)到cache緩存里面 (這時(shí)候key、value值一樣),將緩存有效期設(shè)置為 token有效時(shí)間的2倍。
          2. 當(dāng)該用戶再次請(qǐng)求時(shí),通過(guò)后端的一個(gè)Filter 校驗(yàn)前端token是否是有效token,如果token無(wú)效表明是非法請(qǐng)求,直接拋出異常即可;
          3. 根據(jù)規(guī)則從cache緩存中取出token,判斷cache token是否存在,此時(shí)有以下幾種情況:
            • cache token 不存在 這種情況說(shuō)明token在緩存中過(guò)期了,表明該用戶賬戶空閑時(shí)間過(guò)長(zhǎng),此時(shí)屬于正常過(guò)期,后端直接返回用戶信息已失效,請(qǐng)重新登錄即可。
            • cache token 存在,則需要使用jwt工具類驗(yàn)證該cache token 是否過(guò)期超時(shí),不過(guò)期無(wú)需處理。過(guò)期則表示該用戶一直在操作只是token失效了,后端程序會(huì)給token對(duì)應(yīng)的key映射的value值重新生成 token并覆蓋value值,該緩存生命周期重新計(jì)算。

          實(shí)現(xiàn)邏輯的核心原理:

          前端請(qǐng)求Header中設(shè)置的token保持不變,校驗(yàn)有效性以緩存中的token為準(zhǔn)。

          代碼實(shí)現(xiàn)(偽碼)

          1. 登錄成功后給用戶簽發(fā)token,并設(shè)置token的有效期
          ...
          SysUser?sysUser?=?userService.getUser(username,password);
          if(null?!==?sysUser){
          ????String?token?=?JwtUtil.sign(sysUser.getUsername(),?sysUser.getPassword());
          }
          ...


          public?static?String?sign(String?username,?String?secret)?{
          ????//設(shè)置token有效期為30分鐘
          ?Date?date?=?new?Date(System.currentTimeMillis()?+?30?*?60?*?1000);
          ?//使用HS256生成token,密鑰則是用戶的密碼
          ?Algorithm?algorithm?=?Algorithm.HMAC256(secret);
          ?//?附帶username信息
          ?return?JWT.create().withClaim("username",?username).withExpiresAt(date).sign(algorithm);
          }


          1. 將token存入redis,并設(shè)定過(guò)期時(shí)間,將redis的過(guò)期時(shí)間設(shè)置成token過(guò)期時(shí)間的兩倍
          Sting?tokenKey?=?"sys:user:token"?+?token;
          redisUtil.set(tokenKey,?token);
          redisUtil.expire(tokenKey,?30?*?60?*?2);

          //將token返回給前端用戶
          return?token;
          1. 前端調(diào)用后端接口時(shí)在請(qǐng)求頭中添加token(略)

          2. 過(guò)濾器校驗(yàn)token,校驗(yàn)token有效性

          public?void?doFilter(ServletRequest?req,?ServletResponse?res,?FilterChain?chain)?throws?IOException,?ServletException?{
          ????//從header中獲取token
          ?String?token?=?httpServletRequest.getHeader("token")
          ?if(null?==?token){
          ??throw?new?RuntimeException("illegal?request,token?is?necessary!")
          ?}
          ????//解析token獲取用戶名
          ?String?username?=?JwtUtil.getUsername(token);
          ?//根據(jù)用戶名獲取用戶實(shí)體,在實(shí)際開(kāi)發(fā)中從redis取
          ?User?user?=?userService.findByUser(username);
          ????if(null?==?user){
          ??throw?new?RuntimeException("illegal?request,token?is?Invalid!")
          ????}
          ?//校驗(yàn)token是否失效,自動(dòng)續(xù)期
          ?if(!refreshToken(token,username,user.getPassword())){
          ??throw?new?RuntimeException("illegal?request,token?is?expired!")
          ?}
          ?...
          }


          1. 實(shí)現(xiàn)token的自動(dòng)續(xù)期
          public?boolean?refreshToken(String?token,?String?userName,?String?passWord)?{
          ?Sting?tokenKey?=?"sys:user:token"?+?token?;
          ?String?cacheToken?=?String.valueOf(redisUtil.get(tokenKey));
          ?if?(StringUtils.isNotEmpty(cacheToken))?{
          ??//?校驗(yàn)token有效性,注意需要校驗(yàn)的是緩存中的token
          ??if?(!JwtUtil.verify(cacheToken,?userName,?passWord))?{
          ???String?newToken?=?JwtUtil.sign(userName,?passWord);
          ???//?設(shè)置超時(shí)時(shí)間
          ???redisUtil.set(tokenKey,?newToken)?;
          ???redisUtil.expire(tokenKey,?30?*?60?*?2);
          ??}
          ??return?true;
          ?}
          ?return?false;
          }
          ...

          public?static?boolean?verify(String?token,?String?username,?String?secret)?{
          ?try?{
          ??//?根據(jù)密碼生成JWT效驗(yàn)器
          ??Algorithm?algorithm?=?Algorithm.HMAC256(secret);
          ??JWTVerifier?verifier?=?JWT.require(algorithm).withClaim("username",?username).build();
          ??//?效驗(yàn)TOKEN
          ??DecodedJWT?jwt?=?verifier.verify(token);
          ??return?true;
          ?}?catch?(Exception?exception)?{
          ??return?false;
          ?}
          }

          本文中jwt的相關(guān)操作是基于 com.auth0.java-jwt 實(shí)現(xiàn),大家可以通過(guò)閱讀原文獲取 JWTUtil 工具類。

          小結(jié)

          jwt token實(shí)現(xiàn)邏輯的核心原理是 前端請(qǐng)求Header中設(shè)置的token保持不變,校驗(yàn)有效性以緩存中的token為準(zhǔn),千萬(wàn)不要直接校驗(yàn)Header中的token。實(shí)現(xiàn)原理部分大家好好體會(huì)一下,思路比實(shí)現(xiàn)更重要!

          在看點(diǎn)贊、轉(zhuǎn)發(fā),是對(duì)我最大的鼓勵(lì)。

          ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 你的每個(gè)贊和在看,我都喜歡!

          瀏覽 72
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  成人免费视频在线观看 | 91麻豆一区二区 | 四虎18| 骚逼毛片| www.99精品 |