久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Oauth2 JWT登出(黑名單方案)

 昵稱10087950 2022-09-22 發(fā)布于江蘇

每日中文

人必須瘋狂一次,,不管故事是一個(gè)人,一個(gè)人,,一次旅行,,還是一個(gè)夢(mèng)想,。

一個(gè)人的一生要瘋狂一次,無(wú)論是為一個(gè)人,,一段感情,,經(jīng)歷,還是一個(gè)夢(mèng)想,。

每日掏心話

就像人生今天,,沒(méi)有任何結(jié)果,而是自己,,而不是由己,。如果,只有自己努力了,,努力了,,就好了。

責(zé)編:樂(lè)樂(lè) |來(lái)自blog.csdn.net/lbjfish/article/details/109321044

編程技術(shù)圈(ID:study_tech)第1716 期推文

往日回顧:本科、碩士,、博士的獎(jiǎng)學(xué)金(不要太形象)

      正文     

  大家好,,我是小樂(lè)

圖片

說(shuō)明

先說(shuō)一下,,個(gè)人不建議使用JWT這種token,,還是建議使用RedisTokenStore方案,成熟,。因?yàn)镴WT是無(wú)狀態(tài)的,,這是它的優(yōu)點(diǎn),如果強(qiáng)方式還行給它加比較狀態(tài),,那不如用Session方案,。

不能控制出功能,是官方無(wú)法控制的JwtTokenStore.removeAccessToken一個(gè)方法,;比如實(shí)現(xiàn)續(xù)簽功能,,因?yàn)橥遣荒芸刂频囊环N方法,;一個(gè),每次調(diào)用類似訪問(wèn)的重要,,返回 JWT 的標(biāo)記都不是一樣的(是 jwt 算法,,的時(shí)間,的用戶,,jwt 變),。

Oauth2官方提供JWT明明告訴你,也不建議做登出和續(xù)簽,,它適合后臺(tái)管理系統(tǒng)的內(nèi)部登錄系統(tǒng),,如果幾乎不用這種方式退出和續(xù)簽的情況,也可以退出,,也很簡(jiǎn)單,,可以直接清掉瀏覽器上的token cookie

總結(jié)黑名單方案有具體實(shí)現(xiàn)方式(都是基于重新發(fā)布):

  • ResJwtAccessTokenConverter中新建子RedisJwtClaimsSetVerifier并實(shí)現(xiàn)JwtClaimsSetVerifier接口,。主要是類verify()方法,。

  • ResJwtAccessTokenConverterJWTfaultUserAuthenticationConverter主要是繼承DefaultAccessTokenConverter類。中子類是方法并取得jti extractAuthentication()map.get(“jti”),。

  • 實(shí)現(xiàn)過(guò)濾器LogoutAuthenticationFilter,,在調(diào)登錄接口實(shí)現(xiàn)前,判斷jti,。

那么我更容易實(shí)現(xiàn)第一個(gè),,已經(jīng)可以比其他高,因?yàn)榈谝粋€(gè)是登錄前判斷好,,實(shí)現(xiàn)方式,,所以是auth2的登錄邏輯代碼,可以低效,,選擇還是看自己,,遇到困難很簡(jiǎn)單。

黑名單方式是不適合擴(kuò)展續(xù)簽功能的,,后面我將執(zhí)行續(xù)簽的方式,并解決續(xù)簽方式,,履行在線踢人功能,。

擴(kuò)展JwtTokenStore

如果白領(lǐng)storeAccessToken隊(duì)需要方法,如果任務(wù)回復(fù)需要removeAccessToken方法,,這里是挑選黑科技,,那么當(dāng)需要在removeAccessToken把方法拿來(lái)方法的時(shí)候,把替身是黑底redis內(nèi)的,,把鑰匙當(dāng)后臺(tái)是值redis內(nèi),。 “網(wǎng)上物聯(lián)網(wǎng)平臺(tái)”,,獲取一份驚喜禮包。

@Slf4j
public class CustomJwtTokenStore extends JwtTokenStore {
    private RedisUtil redisUtil;

    public CustomJwtTokenStore(JwtAccessTokenConverter jwtTokenEnhancer, RedisUtil redisUtil) {
        super(jwtTokenEnhancer);
        this.redisUtil = redisUtil;
    }


    /**
     * 這個(gè)暫時(shí)沒(méi)用,,因?yàn)槲矣玫暮诿麊危?nbsp;白名單需要
     * @param token
     * @param authentication
     */

    @Override
    public void storeAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
        super.storeAccessToken(token, authentication);
    }

    @Override
    public void removeAccessToken(OAuth2AccessToken token) {
        if (token.getAdditionalInformation().containsKey('jti')) {
            String jti = token.getAdditionalInformation().get('jti').toString();
//            redisUtil.del(jtiRedisKey(jti));
            int expire = token.getExpiresIn();
            if(expire < 0){
                expire = 1;
            }
            redisUtil.set(jtiRedisKey(jti), token.getValue(), expire);
        }
        super.removeAccessToken(token);
    }

    private String jtiRedisKey(String jti) {
        return SecurityConstants.CACHE_EXPIRE_TOKEN_BLACKLIST + ':' + jti;
    }
}

如果必須證明是否存在許可,,則需要證明是否存在許可,則提示前端是否存在許可,。

下面來(lái)實(shí)現(xiàn)優(yōu)化登出方式并分析我的改進(jìn),。擴(kuò)展:快速開(kāi)發(fā)平臺(tái)

方案一(驗(yàn)證()方法)

該類在ResJwtAccessTokenConverter中的子類中RedisJwtClaimsSetVerifier ,。代碼:

public class RedisJwtClaimsSetVerifier implements JwtClaimsSetVerifier {
 /**
  * 檢查jti是否在Redis中存在(即是否過(guò)期),如過(guò)期則拋異常
  */

 @Override
 public void verify(Map<String, Object> claims) throws InvalidTokenException {
  if (claims.containsKey('jti')) {
   String jti = claims.get('jti').toString();
   Object value = redisUtil.get(jtiRedisKey(jti));
   if (value != null) {
                  //最好繼承InvalidTokenException重新封裝一個(gè)異常
    throw new BusinessException('Invalid token!');
   }
  }
 }

 private String jtiRedisKey(String jti) {
  return SecurityConstants.CACHE_EXPIRE_TOKEN_BLACKLIST + ':' + jti;
 }
}

該在黑指揮部解決問(wèn)題,,但發(fā)現(xiàn)問(wèn)題,,發(fā)現(xiàn)BusinessException(“Invalid token!”)異常,發(fā)現(xiàn)內(nèi)部JwtAccessTokenConverter.decode(String token)最終會(huì)調(diào)出我上面的verify()方法,,verify()結(jié)果發(fā)現(xiàn)異常,,方法異常,無(wú)法解決問(wèn)題,,會(huì)返回我想要的異常信息(這是我的異常Invalid token!),,會(huì)返回解碼自定義返回的異常信息(Cannot convert access token to JSON),其根源如下:

//源碼:
protected Map<String, Object> decode(String token) {
        try {
            Jwt jwt = JwtHelper.decodeAndVerify(token, this.verifier);
            String claimsStr = jwt.getClaims();
            Map<String, Object> claims = this.objectMapper.parseMap(claimsStr);
            if (claims.containsKey('exp') && claims.get('exp'instanceof Integer) {
                Integer intValue = (Integer)claims.get('exp');
                claims.put('exp'new Long((long)intValue));
            }

            this.getJwtClaimsSetVerifier().verify(claims);
            return claims;
        } catch (Exception var6) {
           //這里會(huì)捕獲我的異常,,返回它的異常信息
            throw new InvalidTokenException('Cannot convert access token to JSON', var6);  
        }
    }

要解決這種異常的信息,,只需要在上面判斷異常類型的異常信息時(shí),才需要返回此類異常信息類型中的特定CustomAuthenticationEntryPoint異常BusinessException,,可能會(huì)有一次異常的業(yè)務(wù),,最好繼承InvalidTokenException一個(gè)異常的人物。

@Slf4j
public class CustomAuthenticationEntryPoint extends OAuth2AuthenticationEntryPoint {

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
       //判斷我的異常信息(BusinessException('Invalid token!')) start -------
        if(e.getCause().getCause() instanceof BusinessException){  //最好繼承InvalidTokenException重新封裝一個(gè)異常
            ResponseUtil.responseWriter(false, objectMapper, response, e.getCause().getCause().getMessage(), HttpStatus.UNAUTHORIZED.value());
        }
       //判斷我的異常信息(BusinessException('Invalid token!')) end -------
        ResponseUtil.responseWriter(false, objectMapper, response, e.getMessage(), HttpStatus.UNAUTHORIZED.value());
    }

}

該方案很好,,但似乎有可能在鑒定庫(kù)中刪除,,會(huì)下降。擴(kuò)展:最全的java題

方案二

該類在ResJwtAccessTokenConverter中子類的子類JWTfaultUserAuthenticationConverter中,。代碼如下:

public class JWTfaultUserAuthenticationConverter extends DefaultUserAuthenticationConverter {
   private Collection<? extends GrantedAuthority> defaultAuthorities;

   @Override
   public Authentication extractAuthentication(Map<String, ?> map) {
                //黑名單代碼開(kāi)始
    if(map.containsKey('jti')){
     String jti = (String) map.get('jti');
     Object value = redisUtil.get(jtiRedisKey(jti));
     if (value != null) {
      throw new InvalidTokenException('Invalid token!');
     }
    }
                //黑名單代碼結(jié)束
    if (map.containsKey(USERNAME)) {
     Object principal = map.get(USERNAME);
    // Collection<? extends GrantedAuthority> authorities = getAuthorities(map);
     LoginAppUser loginUser = new LoginAppUser();
     if (principal instanceof Map) {

      loginUser = BeanUtil.mapToBean((Map) principal, LoginAppUser.classtrue);
       

     }
     return new UsernamePasswordAuthenticationToken(loginUser, 'N/A', loginUser.getAuthorities());
    }
    return null;
   }
  }

該性能方案甚至是第一種方案,,但至少比第一種方案合理一些。

圖片圖片圖片圖片圖片圖片

牛啊逼私活必備的N個(gè)開(kāi)源項(xiàng)目,!收藏接,!

方案三(過(guò)濾器)

該主要先判斷在沒(méi)有jti的token之前,重新判斷是在沒(méi)有jti的token,,目錄里有說(shuō)明,直接返回給前端,如果沒(méi)有單獨(dú)走黑鑒定權(quán)流程,,比較高,。

該方案中沒(méi)有分為四種情況,如果你使用網(wǎng)關(guān)(Spring Cloud Gateway)鑒權(quán),則走普通過(guò)濾器,如果使用網(wǎng)關(guān)鑒權(quán),則走網(wǎng)關(guān)WebFlux鑒權(quán),。

普通服務(wù)過(guò)濾器
/**
 * lbj
 * 各微服務(wù) 獲取token時(shí),先判斷此token是否在黑名單(退出會(huì)保存在redis)中,,如果在,,則拋異常,否則不做處理
 */

@Slf4j
//@ConditionalOnProperty(name = 'myyshop.logoutFilter.enabled', havingValue = 'true')
public class LogoutAuthenticationFilter extends OncePerRequestFilter {

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private TokenStore tokenStore;

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String token = request.getHeader('Authorization');
        if(Strings.isBlank(token) || !token.startsWith(CommonConstant.BEARER_TYPE)){
            filterChain.doFilter(request, response);
        }

        String authHeaderValue = AuthUtils.extractToken(request);
        log.info('authHeaderValue={}', authHeaderValue);
        OAuth2AccessToken accessToken = tokenStore.readAccessToken(authHeaderValue);
        if (accessToken.getAdditionalInformation().containsKey('jti')) {
            String jti = accessToken.getAdditionalInformation().get('jti').toString();
            Object value = redisUtil.get(jtiRedisKey(jti));
            if (value != null) {
                ResponseUtil.responseWriter(false, objectMapper, response, 'this is Invalid token!', HttpStatus.UNAUTHORIZED.value());
                return;
            }
        }
        filterChain.doFilter(request, response);
    }

    private String jtiRedisKey(String jti) {
        return SecurityConstants.CACHE_EXPIRE_TOKEN_BLACKLIST + ':' + jti;
    }
}
Spring Cloud 網(wǎng)關(guān)過(guò)濾器
/**
 * lbj
 * Webflux 各微服務(wù) 獲取token時(shí),,先判斷此token是否在黑名單(退出會(huì)保存在redis)中,,如果在,則拋異常,,否則不做處理
 */

public class LogoutAuthenticationWebFilter implements WebFilter {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private TokenStore tokenStore;


    @Override
    public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) {

        ServerHttpRequest request = serverWebExchange.getRequest();
        String token = request.getHeaders().getFirst('Authorization');
        if(Strings.isBlank(token) || !token.startsWith(CommonConstant.BEARER_TYPE)){
            return webFilterChain.filter(serverWebExchange);
        }

        String authHeaderValue = token.substring(CommonConstant.BEARER_TYPE.length()).trim();
        OAuth2AccessToken accessToken = tokenStore.readAccessToken(authHeaderValue);
        if (accessToken.getAdditionalInformation().containsKey('jti')) {
            String jti = accessToken.getAdditionalInformation().get('jti').toString();
            Object value = redisTemplate.opsForValue().get(jtiRedisKey(jti));
            if (value != null) {
                return WebfluxResponseUtil.responseFailed(serverWebExchange, HttpStatus.UNAUTHORIZED.value(), 'Webflux this is Invalid token!');
            }
        }
        return webFilterChain.filter(serverWebExchange);
    }

    private String jtiRedisKey(String jti) {
        return SecurityConstants.CACHE_EXPIRE_TOKEN_BLACKLIST + ':' + jti;
    }
}

有需要的同學(xué),,如果本文對(duì)您有幫助,也請(qǐng)幫忙點(diǎn)個(gè) 贊+在 看啦,!??

你還有什么想要補(bǔ)充的嗎,?

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多