Class JwtTokenProvider

java.lang.Object
io.leandev.appfuse.security.auth.JwtTokenProvider

public class JwtTokenProvider extends Object
  • Field Details

    • CLAIM_TOKEN_TYPE

      public static final String CLAIM_TOKEN_TYPE
      JWT 家族辨識 claim;Resource Server 只接受 TOKEN_TYPE_ACCESS
      See Also:
    • TOKEN_TYPE_ACCESS

      public static final String TOKEN_TYPE_ACCESS
      See Also:
    • TOKEN_TYPE_REFRESH

      public static final String TOKEN_TYPE_REFRESH
      See Also:
    • CLAIM_SESSION_ID

      public static final String CLAIM_SESSION_ID

      Session ID claim 名稱

      用於識別一組 access token 和 refresh token 所屬的會話, 登出時只需將 session ID 加入黑名單,即可同時失效兩種 token。

      See Also:
  • Constructor Details

    • JwtTokenProvider

      public JwtTokenProvider()
  • Method Details

    • generateToken

      public String generateToken(org.springframework.security.core.userdetails.UserDetails userDetails, Map<String,Object> claims, Instant expiryDate)
    • generateToken

      public String generateToken(org.springframework.security.core.userdetails.UserDetails userDetails, Map<String,Object> claims)
    • generateToken

      public String generateToken(org.springframework.security.core.userdetails.UserDetails userDetails, Instant expiryDate)
    • generateToken

      public String generateToken(org.springframework.security.core.userdetails.UserDetails userDetails, Map<String,Object> claims, long jwtExpirationInMs)
    • generateToken

      public String generateToken(org.springframework.security.core.userdetails.UserDetails userDetails, long jwtExpirationInMs)
    • generateToken

      public String generateToken(org.springframework.security.core.Authentication authentication, Map<String,Object> claims)
    • generateToken

      public String generateToken(org.springframework.security.core.Authentication authentication)
    • generateRefreshToken

      public String generateRefreshToken(org.springframework.security.core.Authentication authentication, Map<String,Object> claims)

      產生 Refresh Token

      Refresh Token 使用較長的過期時間,並包含 tokenType claim 以區分。

      Parameters:
      authentication - 認證資訊
      claims - 額外的 claims
      Returns:
      Refresh Token
    • generateRefreshToken

      public String generateRefreshToken(org.springframework.security.core.userdetails.UserDetails userDetails, Map<String,Object> claims)
      產生 Refresh Token
      Parameters:
      userDetails - 用戶資訊
      claims - 額外的 claims
      Returns:
      Refresh Token
    • getRefreshTokenExpirationInMs

      public long getRefreshTokenExpirationInMs()
      取得 Refresh Token 過期時間(毫秒)
    • generateDelegationToken

      public String generateDelegationToken(org.springframework.security.core.userdetails.UserDetails subject, List<String> grantors, Map<String,Object> extraClaims)

      產生代理(Delegation)token

      sub 維持登入者、authsubject 的權限(呼叫端應先把「借用 ROLE 展開的權限」 併入 subject.getAuthorities())、帶 grantors claim(代理維)。 載入代理對象、選哪些 ROLE、決定是否允許皆由應用層負責(框架不做管控,見 ADR-013)。 要同時具模擬維,於 extraClaims 併入 ActingClaims.impersonation(String)(無 key 衝突)。

      Parameters:
      subject - 登入者,其 authorities 應為「自身 ∪ 借用 ROLE 權限」的合併結果
      grantors - 代理授權人 stable subject 集合(至少一筆,供稽核與 instance 級過濾)
      extraClaims - 其他 claim(如 tenantIdsessionId);可為 null
      Returns:
      代理 access token
    • generateImpersonationToken

      public String generateImpersonationToken(org.springframework.security.core.userdetails.UserDetails impersonatedSubject, String actor, Map<String,Object> extraClaims)

      產生模擬(Impersonation)token

      sub/auth 換成被模擬者(傳入的 impersonatedSubject)、帶 actor claim(模擬維)。 被模擬者的 tenantId 由呼叫端於 extraClaims 帶入(模擬可跨租戶,見 ADR-013)。 要同時具代理維(如被模擬者本身被指派代理),於 extraClaims 併入 ActingClaims.delegation(List)(無 key 衝突,ActingContext 兩維皆讀得到)。

      Parameters:
      impersonatedSubject - 被模擬者(其 stable subject/authorities 即 token 的 sub/auth
      actor - 真實操作者(模擬者)的 stable subject,供結束模擬與稽核
      extraClaims - 其他 claim(如被模擬者 tenantIdsessionId);可為 null
      Returns:
      模擬 access token
    • getPublicKey

      public PublicKey getPublicKey()

      取得簽章驗證用的公鑰

      供資源伺服器以本地公鑰建立 JwtDecoder(STANDALONE 模式驗自簽 token, 見 io.leandev.appfuse.security.resourceserver.ResourceServerFactory)。

      Returns:
      JWT 簽章驗證公鑰(RSA)
    • getUsernameFromJwt

      public String getUsernameFromJwt(String token)
    • getClaimsFromJwt

      public io.jsonwebtoken.Claims getClaimsFromJwt(String token)
    • getSessionIdFromJwt

      public String getSessionIdFromJwt(String token)
      從 JWT token 中取得 session ID
      Parameters:
      token - JWT token(access 或 refresh token)
      Returns:
      session ID,若不存在則回傳 null
    • validateToken

      public void validateToken(String authToken) throws io.jsonwebtoken.JwtException
      Throws:
      io.jsonwebtoken.JwtException
    • refreshToken

      public String refreshToken(String refreshToken) throws io.jsonwebtoken.JwtException

      使用 Refresh Token 產生新的 Access Token(逐字複製 refresh token 的既有 claims)。

      ⚠️ 不保留 authorities:本方法把 refresh token 的 claims 原樣搬到新 access token, 而 refresh token 由 generateRefreshToken(Authentication, Map) 產生、不帶 auth(authorities)claim (見該方法)。因此本方法產出的 access token 沒有 authorities——以標準 oauth2ResourceServer().jwt() 驗證時會被解讀為「零權限」,導致需細粒度授權 (hasAuthority(...))的端點回 403,而角色型/公開端點仍可存取(不易察覺)。

      正確用法:需要鑄帶權限的 access token(互動式 session 刷新)的呼叫端,不要用本方法 的產物當 access token;應改為依 sub 重新載入使用者當前權限(UserDetailsService), 再以 generateToken(UserDetails, Map) 鑄新 token(保留 refresh token 的 sessionId 等 carry claims)。本方法可續用於「驗證 refresh token 有效性/型別」等不消費其產物的場景。 參考落點:app-server AuthController.refresh

      Parameters:
      refreshToken - Refresh Token
      Returns:
      新的 Access Token(不含 authorities,見上方警告)
      Throws:
      io.jsonwebtoken.JwtException - 如果 token 無效或不是 refresh token