欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringSecurity Jwt Token 自動刷新的實現(xiàn)

 更新時間:2020年06月08日 11:49:12   作者:huan1993  
這篇文章主要介紹了SpringSecurity Jwt Token 自動刷新的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

功能需求

        最近項目中有這么一個功能,用戶登錄系統(tǒng)后,需要給 用戶 頒發(fā)一個 token ,后續(xù)訪問系統(tǒng)的請求都需要帶上這個 token ,如果請求沒有帶上這個 token 或者 token 過期了,那么禁止訪問系統(tǒng)。如果用戶一直訪問系統(tǒng),那么還需要自動延長 token 的過期時間。

功能分析

1、token 的生成

使用現(xiàn)在比較流行的 jwt 來生成。

2、token 的自動延長

要實現(xiàn) token 的自動延長,系統(tǒng)給用戶 頒發(fā) 一個 token 無法實現(xiàn),那么通過變通一個,給用戶生成 2個 token ,一個用于 api 訪問的 token ,一個 用于在 token 過期的時候 用來 刷新 的 refreshToken。并且 refreshToken 的 生命周期要比 token 的生命周期長。

3、系統(tǒng)資源的保護(hù)

可以使用Spring Security 來保護(hù)系統(tǒng)的各種資源。

4、用戶如何傳遞 token

系統(tǒng)中 tokenrefreshToken 的傳遞一律放在請求頭。

實現(xiàn)思路

1、生成 token 和 refreshToken

用戶登錄系統(tǒng)的時候,后臺給用戶生成 tokenrefreshToken 并放在響應(yīng)頭中返回

2、系統(tǒng) 判斷 token 是否合法

  • token 未失效的時的處理
  • token 失效 ,如何使用refreshToken來生成新的 token

核心代碼如下

1、過濾器代碼,token判斷和再次生成

package com.huan.study.security.token;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.huan.study.security.configuration.TokenProperties;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * @author huan 2020-06-07 - 14:34
 */
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Slf4j
public class TokenAuthenticateFilter extends OncePerRequestFilter {

  private final TokenProperties tokenProperties;
  private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

  @Override
  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
    // 獲取 認(rèn)證頭
    String authorizationHeader = request.getHeader(tokenProperties.getAuthorizationHeaderName());
    if (!checkIsTokenAuthorizationHeader(authorizationHeader)) {
      log.debug("獲取到認(rèn)證頭Authorization的值:[{}]但不是我們系統(tǒng)中登錄后簽發(fā)的。", authorizationHeader);
      filterChain.doFilter(request, response);
      return;
    }
    // 獲取到真實的token
    String realToken = getRealAuthorizationToken(authorizationHeader);
    // 解析 jwt token
    Jws<Claims> jws = JwtUtils.parserAuthenticateToken(realToken, tokenProperties.getSecretKey());
    // token 不合法
    if (null == jws) {
      writeJson(response, "認(rèn)證token不合法");
      return;
    }
    // token 是否過期
    if (JwtUtils.isJwtExpired(jws)) {
      // 處理過期
      handleTokenExpired(response, request, filterChain);
      return;
    }

    // 構(gòu)建認(rèn)證對象
    JwtUtils.buildAuthentication(jws, tokenProperties.getUserId());

    filterChain.doFilter(request, response);
  }

  /**
   * 處理token過期情況
   *
   * @param response
   * @param request
   * @param filterChain
   * @return
   * @throws IOException
   */
  private void handleTokenExpired(HttpServletResponse response, HttpServletRequest request, FilterChain filterChain) throws IOException, ServletException {
    // 獲取刷新 token
    String refreshTokenHeader = request.getHeader(tokenProperties.getRefreshHeaderName());
    // 檢測 refresh-token 是否是我們系統(tǒng)中簽發(fā)的
    if (!checkIsTokenAuthorizationHeader(refreshTokenHeader)) {
      log.debug("獲取到刷新認(rèn)證頭:[{}]的值:[{}]但不是我們系統(tǒng)中登錄后簽發(fā)的。", tokenProperties.getRefreshHeaderName(), refreshTokenHeader);
      writeJson(response, "token過期了,refresh token 不是我們系統(tǒng)簽發(fā)的");
      return;
    }
    // 解析 refresh-token
    Jws<Claims> refreshToken = JwtUtils.parserAuthenticateToken(getRealAuthorizationToken(refreshTokenHeader),
        tokenProperties.getSecretKey());
    // 判斷 refresh-token 是否不合法
    if (null == refreshToken) {
      writeJson(response, "refresh token不合法");
      return;
    }
    // 判斷 refresh-token 是否過期
    if (JwtUtils.isJwtExpired(refreshToken)) {
      writeJson(response, "refresh token 過期了");
      return;
    }
    // 重新簽發(fā) token

    String newToken = JwtUtils.generatorJwtToken(
        refreshToken.getBody().get(tokenProperties.getUserId()),
        tokenProperties.getUserId(),
        tokenProperties.getTokenExpireSecond(),
        tokenProperties.getSecretKey()
    );
    response.addHeader(tokenProperties.getAuthorizationHeaderName(), newToken);

    // 構(gòu)建認(rèn)證對象
    JwtUtils.buildAuthentication(JwtUtils.parserAuthenticateToken(newToken, tokenProperties.getSecretKey()), tokenProperties.getUserId());

    filterChain.doFilter(request, response);
  }

  /**
   * 寫 json 數(shù)據(jù)給前端
   *
   * @param response
   * @throws IOException
   */
  private void writeJson(HttpServletResponse response, String msg) throws IOException {
    response.setCharacterEncoding(StandardCharsets.UTF_8.name());
    response.setContentType(MediaType.APPLICATION_JSON_VALUE);
    response.setStatus(HttpStatus.UNAUTHORIZED.value());
    Map<String, String> params = new HashMap<>(4);
    params.put("msg", msg);
    response.getWriter().print(OBJECT_MAPPER.writeValueAsString(params));
  }

  /**
   * 獲取到真實的 token 串
   *
   * @param authorizationToken
   * @return
   */
  private String getRealAuthorizationToken(String authorizationToken) {
    return StringUtils.substring(authorizationToken, tokenProperties.getTokenHeaderPrefix().length()).trim();
  }

  /**
   * 判斷是否是系統(tǒng)中登錄后簽發(fā)的token
   *
   * @param authorizationHeader
   * @return
   */
  private boolean checkIsTokenAuthorizationHeader(String authorizationHeader) {
    if (StringUtils.isBlank(authorizationHeader)) {
      return false;
    }
    if (!StringUtils.startsWith(authorizationHeader, tokenProperties.getTokenHeaderPrefix())) {
      return false;
    }
    return true;
  }
}

2、jwt 工具類代碼

package com.huan.study.security.token;

import io.jsonwebtoken.*;
import io.jsonwebtoken.impl.DefaultJws;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;

/**
 * jwt 工具類
 *
 * @author huan
 * @date 2020-05-20 - 17:09
 */
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class JwtUtils {

  /**
   * 解析 jwt token
   *
   * @param token   需要解析的json
   * @param secretKey 密鑰
   * @return
   */
  public static Jws<Claims> parserAuthenticateToken(String token, String secretKey) {
    try {
      final Jws<Claims> claimsJws = Jwts.parser()
          .setSigningKey(secretKey)
          .parseClaimsJws(token);
      return claimsJws;
    } catch (ExpiredJwtException e) {
      return new DefaultJws<>(null, e.getClaims(), "");
    } catch (UnsupportedJwtException | MalformedJwtException | SignatureException | IllegalArgumentException | IncorrectClaimException e) {
      log.error(e.getMessage(), e);
      return null;
    }
  }

  /**
   * 判斷 jwt 是否過期
   *
   * @param jws
   * @return true:過期 false:沒過期
   */
  public static boolean isJwtExpired(Jws<Claims> jws) {
    return jws.getBody().getExpiration().before(new Date());
  }

  /**
   * 構(gòu)建認(rèn)證過的認(rèn)證對象
   */
  public static Authentication buildAuthentication(Jws<Claims> jws, String userIdFieldName) {
    Object userId = jws.getBody().get(userIdFieldName);
    TestingAuthenticationToken testingAuthenticationToken = new TestingAuthenticationToken(userId, null, new ArrayList<>(0));
    SecurityContextHolder.getContext().setAuthentication(testingAuthenticationToken);
    return SecurityContextHolder.getContext().getAuthentication();
  }

  /**
   * 生成 jwt token
   */
  public static String generatorJwtToken(Object loginUserId, String userIdFieldName, Long expireSecond, String secretKey) {
    Date expireTime = Date.from(LocalDateTime.now().plusSeconds(expireSecond).atZone(ZoneId.systemDefault()).toInstant());
    return Jwts.builder()
        .setHeaderParam("typ", "JWT")
        .setIssuedAt(new Date())
        .setExpiration(expireTime)
        .claim(userIdFieldName, loginUserId)
        .signWith(SignatureAlgorithm.HS256, secretKey)
        .compact();
  }
}

完整代碼

代碼 https://gitee.com/huan1993/Spring-Security/tree/master/spring-security-jwt

到此這篇關(guān)于SpringSecurity Jwt Token 自動刷新的實現(xiàn)的文章就介紹到這了,更多相關(guān)SpringSecurity 自動刷新內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java高效實現(xiàn)電商產(chǎn)品排序?qū)崙?zhàn)

    Java高效實現(xiàn)電商產(chǎn)品排序?qū)崙?zhàn)

    這篇文章主要為大家介紹了Java高效實現(xiàn)電商產(chǎn)品排序?qū)崙?zhàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • Java中Socket用法詳解

    Java中Socket用法詳解

    本文詳細(xì)講解了Java中Socket的用法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-12-12
  • java基于socket傳輸zip文件功能示例

    java基于socket傳輸zip文件功能示例

    這篇文章主要介紹了java基于socket傳輸zip文件功能,結(jié)合實例形式分析了java使用socket進(jìn)行文件傳輸?shù)木唧w操作步驟與服務(wù)器端、客戶端相關(guān)實現(xiàn)技巧,需要的朋友可以參考下
    2017-07-07
  • Maven項目繼承實現(xiàn)過程圖解

    Maven項目繼承實現(xiàn)過程圖解

    這篇文章主要介紹了Maven項目繼承實現(xiàn)過程圖解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-08-08
  • MapStruct對象映射轉(zhuǎn)換解決Bean屬性拷貝性能問題

    MapStruct對象映射轉(zhuǎn)換解決Bean屬性拷貝性能問題

    無意間看到項目中有小伙伴用到了 MapStruct 來做對象映射轉(zhuǎn)換當(dāng)時我就很好奇,這個是什么框架,能夠解決什么問題,帶著這兩個疑問就有了下面的文章
    2022-02-02
  • SpringBoot整合XxlJob分布式任務(wù)調(diào)度平臺

    SpringBoot整合XxlJob分布式任務(wù)調(diào)度平臺

    xxl-job是一個開源的分布式定時任務(wù)框架,它可以與其他微服務(wù)組件一起構(gòu)成微服務(wù)集群。它的調(diào)度中心(xxl-job)和執(zhí)行器(自己的springboot項目中有@XxlJob("定時任務(wù)名稱")的方法)是相互分離,分開部署的,兩者通過HTTP協(xié)議進(jìn)行通信
    2023-02-02
  • Spring?Boot與Redis的緩存一致性問題解決

    Spring?Boot與Redis的緩存一致性問題解決

    在使用緩存時,緩存一致性問題是一個常見的挑戰(zhàn),本文主要介紹了Spring?Boot與Redis的緩存一致性問題,具有一定的參考價值,感興趣的可以了解一下
    2024-07-07
  • Spring條件注解@ConditionnalOnClass的原理分析

    Spring條件注解@ConditionnalOnClass的原理分析

    這篇文章主要介紹了Spring條件注解@ConditionnalOnClass的原理分析,所謂@ConditionalOnClass注解,翻譯過來就是基于class的條件,它為所標(biāo)注的類或方法添加限制條件,當(dāng)該條件的值為true時,其所標(biāo)注的類或方法才能生效,需要的朋友可以參考下
    2023-12-12
  • Springboot使用redis進(jìn)行api防刷限流過程詳解

    Springboot使用redis進(jìn)行api防刷限流過程詳解

    這篇文章主要介紹了Springboot使用redis進(jìn)行api防刷限流過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-12-12
  • Java?Maven構(gòu)建工具中mvnd和Gradle誰更快

    Java?Maven構(gòu)建工具中mvnd和Gradle誰更快

    這篇文章主要介紹了Java?Maven構(gòu)建工具中mvnd和Gradle誰更快,mvnd?是?Maven?Daemon?的縮寫?,翻譯成中文就是?Maven?守護(hù)進(jìn)程,下文更多相關(guān)資料,需要的小伙伴可以參考一下
    2022-05-05

最新評論