国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

簽發(fā)的用戶認(rèn)證token超時(shí)刷新策略

e10101 / 1402人閱讀

摘要:簽發(fā)的用戶認(rèn)證超時(shí)刷新策略這個(gè)模塊分離至項(xiàng)目權(quán)限管理系統(tǒng)與前后端分離實(shí)踐,感覺那樣太長了找不到重點(diǎn),分離出來要好點(diǎn)。這樣在有效期過后的時(shí)間段內(nèi)可以申請(qǐng)刷新。

簽發(fā)的用戶認(rèn)證token超時(shí)刷新策略

這個(gè)模塊分離至項(xiàng)目api權(quán)限管理系統(tǒng)與前后端分離實(shí)踐,感覺那樣太長了找不到重點(diǎn),分離出來要好點(diǎn)。

對(duì)于登錄的用戶簽發(fā)其對(duì)應(yīng)的jwt,我們?cè)趈wt設(shè)置他的固定有效期時(shí)間,在有效期內(nèi)用戶攜帶jwt訪問沒問題,當(dāng)過有效期后jwt失效,用戶需要重新登錄獲取新的jwt。這個(gè)體驗(yàn)不太好,好的體驗(yàn)應(yīng)該是:活躍的用戶應(yīng)該在無感知的情況下在jwt失效后獲取到新的jwt,攜帶這個(gè)新的jwt進(jìn)行訪問,而長時(shí)間不活躍的用戶應(yīng)該在jwt失效后需要進(jìn)行重新的登錄認(rèn)證。

這里就涉及到了token的超時(shí)刷新問題,解決方案看圖:

在簽發(fā)有效期為 t 時(shí)間的jwt后,把jwt用("JWT-SESSION-"+appId,jwt)的key-value形式存儲(chǔ)到redis中,有效期設(shè)置為2倍的 t 。這樣jwt在有效期過后的 t 時(shí)間段內(nèi)可以申請(qǐng)刷新token。
還有個(gè)問題是用戶攜帶過期的jwt對(duì)后臺(tái)請(qǐng)求,在可刷新時(shí)間段內(nèi)返回了新的jwt,應(yīng)該在用戶無感知的情況下返回請(qǐng)求的內(nèi)容,而不是接收一個(gè)刷新的jwt。我們是不是可以在每次request請(qǐng)求回調(diào)的時(shí)候判斷返回的是不是刷新jwt,但是判斷是之后我們是否放棄之前的用戶請(qǐng)求,如果不放棄,那是不是應(yīng)該在最開始的用戶request請(qǐng)求前先保存這個(gè)請(qǐng)求,在之后的回調(diào)中如果是返回刷新jwt,我們?cè)贁y帶這個(gè)新的jwt再請(qǐng)求一次保存好的request請(qǐng)求?但對(duì)于前端這么大量的不同請(qǐng)求,這樣是不是太麻煩了?

這困擾了我很久哎,直到我用到了angualr的HttpInterceptor哈哈哈哈哈哈哈哈哈哈哈哈哈哈。

angualr的HttpInterceptor就是前端的攔截過濾器,發(fā)起請(qǐng)求會(huì)攔截處理,接收請(qǐng)求也會(huì)攔截處理。最大的好處對(duì)每次的原始request他都會(huì)完整的保存下來,我們向后臺(tái)發(fā)生的request是他的clone。next.handle(request.clone)
繼承HttpInterceptor的AuthInterceptor,攔截response判斷是否為refresh token,是則攜帶新token再次發(fā)起保存的request:

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

  constructor(private authService: AuthService, private router: Router) {}

  intercept(req: HttpRequest, next: HttpHandler): Observable> {
    const authToken = this.authService.getAuthorizationToken();
    const uid = this.authService.getUid();
    let authReq: any;
    if (authToken != null && uid != null) {
      authReq = req.clone({
        setHeaders: {
          "authorization": authToken,
          "appId": uid
        }
      });
    } else {
      authReq = req.clone();
    }

    console.log(authReq);
    return next.handle(authReq).pipe(
      mergeMap(event => {
        // 返回response
        if (event instanceof HttpResponse) {
          if (event.status === 200) {
            // 若返回JWT過期但refresh token未過期,返回新的JWT 狀態(tài)碼為1005
            if (event.body.meta.code === 1005) {
              const jwt = event.body.data.jwt;
              // 更新AuthorizationToken
              this.authService.updateAuthorizationToken(jwt);
              // clone request 重新發(fā)起請(qǐng)求
              // retry(1);
              authReq = req.clone({
                setHeaders: {
                  "authorization": jwt,
                  "appId": uid
                }
              });
              return next.handle(authReq);

            }
          }
          if (event.status === 404) {
            // go to 404 html
            this.router.navigateByUrl("/404");
          }
          if (event.status === 500) {
            // go to 500 html
            this.router.navigateByUrl("/500");
          }
        }
        console.log(event);
        // 返回正常情況的可觀察對(duì)象
        return of(event);
      }),
      catchError(this.handleError)
    );
  }

  private handleError(error: HttpErrorResponse) {
    if (error.error instanceof ErrorEvent) {
      // A client-side or network error occurred. Handle it accordingly.
      console.error("An error occurred:", error.error.message);
    } else {
      console.error( `Backend returned code ${error.status}, ` +
        `body was: ${error.error}`);
    }
    repeat(1);
    return new ErrorObservable("親請(qǐng)檢查網(wǎng)絡(luò)");

  }
}

后端簽發(fā)jwt時(shí)所做的:

 /* *
     * @Description 這里已經(jīng)在 passwordFilter 進(jìn)行了登錄認(rèn)證
     * @Param [] 登錄簽發(fā) JWT
     * @Return java.lang.String
     */
    @ApiOperation(value = "用戶登錄",notes = "POST用戶登錄簽發(fā)JWT")
    @PostMapping("/login")
    public Message accountLogin(HttpServletRequest request, HttpServletResponse response) {
        Map params = RequestResponseUtil.getRequestParameters(request);
        String appId = params.get("appId");
        // 根據(jù)appId獲取其對(duì)應(yīng)所擁有的角色(這里設(shè)計(jì)為角色對(duì)應(yīng)資源,沒有權(quán)限對(duì)應(yīng)資源)
        String roles = accountService.loadAccountRole(appId);
        // 時(shí)間以秒計(jì)算,token有效刷新時(shí)間是token有效過期時(shí)間的2倍
        long refreshPeriodTime = 36000L;
        String jwt = JsonWebTokenUtil.issueJWT(UUID.randomUUID().toString(),appId,
                "token-server",refreshPeriodTime >> 2,roles,null, SignatureAlgorithm.HS512);
        // 將簽發(fā)的JWT存儲(chǔ)到Redis: {JWT-SESSION-{appID} , jwt}
        redisTemplate.opsForValue().set("JWT-SESSION-"+appId,jwt,refreshPeriodTime, TimeUnit.SECONDS);
        AuthUser authUser = userService.getUserByAppId(appId);

        return new Message().ok(1003,"issue jwt success").addData("jwt",jwt).addData("user",authUser);
    }

后端refresh token時(shí)所做的:

protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object mappedValue) throws Exception {
        Subject subject = getSubject(servletRequest,servletResponse);
        // 判斷是否為JWT認(rèn)證請(qǐng)求
        if ((null == subject || !subject.isAuthenticated()) && isJwtSubmission(servletRequest)) {
            AuthenticationToken token = createJwtToken(servletRequest);
            try {
                subject.login(token);
//                return this.checkRoles(subject,mappedValue) && this.checkPerms(subject,mappedValue);
                return this.checkRoles(subject,mappedValue);
            }catch (AuthenticationException e) {
                LOGGER.info(e.getMessage(),e);
                // 如果是JWT過期
                if (e.getMessage().equals("expiredJwt")) {
                    // 這里初始方案先拋出令牌過期,之后設(shè)計(jì)為在Redis中查詢當(dāng)前appId對(duì)應(yīng)令牌,其設(shè)置的過期時(shí)間是JWT的兩倍,此作為JWT的refresh時(shí)間
                    // 當(dāng)JWT的有效時(shí)間過期后,查詢其refresh時(shí)間,refresh時(shí)間有效即重新派發(fā)新的JWT給客戶端,
                    // refresh也過期則告知客戶端JWT時(shí)間過期重新認(rèn)證

                    // 當(dāng)存儲(chǔ)在redis的JWT沒有過期,即refresh time 沒有過期
                    String appId = WebUtils.toHttp(servletRequest).getHeader("appId");
                    String jwt = WebUtils.toHttp(servletRequest).getHeader("authorization");
                    String refreshJwt = redisTemplate.opsForValue().get("JWT-SESSION-"+appId);
                    if (null != refreshJwt && refreshJwt.equals(jwt)) {
                        // 重新申請(qǐng)新的JWT
                        // 根據(jù)appId獲取其對(duì)應(yīng)所擁有的角色(這里設(shè)計(jì)為角色對(duì)應(yīng)資源,沒有權(quán)限對(duì)應(yīng)資源)
                        String roles = accountService.loadAccountRole(appId);
                        long refreshPeriodTime = 36000L;  //seconds為單位,10 hours
                        String newJwt = JsonWebTokenUtil.issueJWT(UUID.randomUUID().toString(),appId,
                                "token-server",refreshPeriodTime >> 2,roles,null, SignatureAlgorithm.HS512);
                        // 將簽發(fā)的JWT存儲(chǔ)到Redis: {JWT-SESSION-{appID} , jwt}
                        redisTemplate.opsForValue().set("JWT-SESSION-"+appId,newJwt,refreshPeriodTime, TimeUnit.SECONDS);
                        Message message = new Message().ok(1005,"new jwt").addData("jwt",newJwt);
                        RequestResponseUtil.responseWrite(JSON.toJSONString(message),servletResponse);
                        return false;
                    }else {
                        // jwt時(shí)間失效過期,jwt refresh time失效 返回jwt過期客戶端重新登錄
                        Message message = new Message().error(1006,"expired jwt");
                        RequestResponseUtil.responseWrite(JSON.toJSONString(message),servletResponse);
                        return false;
                    }

                }
                // 其他的判斷為JWT錯(cuò)誤無效
                Message message = new Message().error(1007,"error Jwt");
                RequestResponseUtil.responseWrite(JSON.toJSONString(message),servletResponse);
                return false;

            }catch (Exception e) {
                // 其他錯(cuò)誤
                LOGGER.warn(servletRequest.getRemoteAddr()+"JWT認(rèn)證"+e.getMessage(),e);
                // 告知客戶端JWT錯(cuò)誤1005,需重新登錄申請(qǐng)jwt
                Message message = new Message().error(1007,"error jwt");
                RequestResponseUtil.responseWrite(JSON.toJSONString(message),servletResponse);
                return false;
            }
        }else {
            // 請(qǐng)求未攜帶jwt 判斷為無效請(qǐng)求
            Message message = new Message().error(1111,"error request");
            RequestResponseUtil.responseWrite(JSON.toJSONString(message),servletResponse);
            return false;
        }
    }


效果展示




github:
bootshiro
usthe

碼云:
bootshiro
usthe



持續(xù)更新。。。。。。


分享一波阿里云代金券快速上云

轉(zhuǎn)載請(qǐng)注明 from tomsun28

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/69182.html

相關(guān)文章

  • 前后端分離——token超時(shí)刷新策略

    摘要:實(shí)現(xiàn)目標(biāo)延長過期時(shí)間活躍用戶在過期時(shí),在用戶無感知的情況下動(dòng)態(tài)刷新,做到一直在線狀態(tài)不活躍用戶在過期時(shí),直接定向到登錄頁登錄返回字段如何簽發(fā),請(qǐng)看上一篇推文,這里不做過多介紹。如果你有更好的做法,歡迎留言告知我,謝謝啦。 前言 記錄一下前后端分離下————token超時(shí)刷新策略! 需求場景 昨天發(fā)了一篇記錄 前后端分離應(yīng)用——用戶信息傳遞 中介紹了token認(rèn)證機(jī)制,跟幾位群友討論了...

    hatlonely 評(píng)論0 收藏0
  • api權(quán)限管理系統(tǒng)與前后端分離實(shí)踐

    摘要:自己在前后端分離上的實(shí)踐要想實(shí)現(xiàn)完整的前后端分離,安全這塊是繞不開的,這個(gè)系統(tǒng)主要功能就是動(dòng)態(tài)管理,這次實(shí)踐包含兩個(gè)模塊基于搭建的權(quán)限管理系統(tǒng)后臺(tái)編寫的前端管理。 自己在前后端分離上的實(shí)踐 要想實(shí)現(xiàn)完整的前后端分離,安全這塊是繞不開的,這個(gè)系統(tǒng)主要功能就是動(dòng)態(tài)restful api管理,這次實(shí)踐包含兩個(gè)模塊,基于springBoot + shiro搭建的權(quán)限管理系統(tǒng)后臺(tái)bootshir...

    bawn 評(píng)論0 收藏0
  • api權(quán)限管理系統(tǒng)與前后端分離實(shí)踐

    摘要:自己在前后端分離上的實(shí)踐要想實(shí)現(xiàn)完整的前后端分離,安全這塊是繞不開的,這個(gè)系統(tǒng)主要功能就是動(dòng)態(tài)管理,這次實(shí)踐包含兩個(gè)模塊基于搭建的權(quán)限管理系統(tǒng)后臺(tái)編寫的前端管理。 自己在前后端分離上的實(shí)踐 要想實(shí)現(xiàn)完整的前后端分離,安全這塊是繞不開的,這個(gè)系統(tǒng)主要功能就是動(dòng)態(tài)restful api管理,這次實(shí)踐包含兩個(gè)模塊,基于springBoot + shiro搭建的權(quán)限管理系統(tǒng)后臺(tái)bootshir...

    tianlai 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<