中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

SpringSecurity Jwt Token如何實現自動刷新

發布時間:2020-07-18 11:02:22 來源:億速云 閱讀:333 作者:小豬 欄目:編程語言

這篇文章主要為大家展示了SpringSecurity Jwt Token如何實現自動刷新,內容簡而易懂,希望大家可以學習一下,學習完之后肯定會有收獲的,下面讓小編帶大家一起來看看吧。

功能需求

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

功能分析

1、token 的生成

使用現在比較流行的 jwt 來生成。

2、token 的自動延長

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

3、系統資源的保護

可以使用Spring Security 來保護系統的各種資源。

4、用戶如何傳遞 token

系統中 tokenrefreshToken 的傳遞一律放在請求頭。

實現思路

1、生成 token 和 refreshToken

用戶登錄系統的時候,后臺給用戶生成 tokenrefreshToken 并放在響應頭中返回

2、系統 判斷 token 是否合法

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

SpringSecurity Jwt 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 {
    // 獲取 認證頭
    String authorizationHeader = request.getHeader(tokenProperties.getAuthorizationHeaderName());
    if (!checkIsTokenAuthorizationHeader(authorizationHeader)) {
      log.debug("獲取到認證頭Authorization的值:[{}]但不是我們系統中登錄后簽發的。", 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, "認證token不合法");
      return;
    }
    // token 是否過期
    if (JwtUtils.isJwtExpired(jws)) {
      // 處理過期
      handleTokenExpired(response, request, filterChain);
      return;
    }

    // 構建認證對象
    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 是否是我們系統中簽發的
    if (!checkIsTokenAuthorizationHeader(refreshTokenHeader)) {
      log.debug("獲取到刷新認證頭:[{}]的值:[{}]但不是我們系統中登錄后簽發的。", tokenProperties.getRefreshHeaderName(), refreshTokenHeader);
      writeJson(response, "token過期了,refresh token 不是我們系統簽發的");
      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;
    }
    // 重新簽發 token

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

    // 構建認證對象
    JwtUtils.buildAuthentication(JwtUtils.parserAuthenticateToken(newToken, tokenProperties.getSecretKey()), tokenProperties.getUserId());

    filterChain.doFilter(request, response);
  }

  /**
   * 寫 json 數據給前端
   *
   * @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();
  }

  /**
   * 判斷是否是系統中登錄后簽發的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());
  }

  /**
   * 構建認證過的認證對象
   */
  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();
  }
}

以上就是關于SpringSecurity Jwt Token如何實現自動刷新的內容,如果你們有學習到知識或者技能,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

武宣县| 长白| 安仁县| 临沭县| 黑龙江省| 资源县| 叙永县| 揭阳市| 米林县| 江北区| 舟山市| 疏附县| 清镇市| 射阳县| 成安县| 马尔康县| 朝阳县| 镇江市| 邹城市| 临清市| 太白县| 大庆市| 阜新| 富锦市| 荥阳市| 鹤庆县| 温泉县| 浮山县| 武川县| 辽宁省| 岳西县| 石台县| 徐汇区| 忻州市| 竹北市| 朝阳区| 平凉市| 陕西省| 鱼台县| 高唐县| 台东市|