iT邦幫忙

2023 iThome 鐵人賽

DAY 14
0
Mobile Development

Android與Spring Boot開發學習之旅系列 第 14

開發學習之旅 Day14 - 使用 JSON Web Token 進行身份驗證(一)

  • 分享至 

  • xImage
  •  

JSON Web Token 是一種用於網路上安全傳輸信息的標準。在Spring Boot應用程序中,常被用於實現身份驗證和授權機制。身份驗證過程中,當使用者成功登錄後,會生成JWT並返回給客戶端,後續將JWT包含在請求的標頭中會使用密鑰來驗證JWT的簽名,如果JWT是有效的且未過期,表示可以信任其中的聲明並授予訪問。JWT通常由三部分組成:

  • Header:包含令牌的類型與使用的簽名算法。
  • Payload:包含要傳遞的信息(聲名),例如使用者的角色等。
  • Signature:用於驗證令牌的完整性。

JWT的優點:

  • 無需在伺服器端保存使用者狀態
    • 每個JWT包含了所有必要的信息,無須特別紀錄。
  • 安全性
    • 因為有簽名機制,所以可以驗證JWT的完整性,確保未被篡改。

添加依賴

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.5</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.11.5</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>0.11.5</version>
</dependency>

產生密鑰

可以使用ez2o工具生成密鑰
https://ithelp.ithome.com.tw/upload/images/20230924/20150372pnM4RfqtTf.png

創建一個JWT工具類(JwtService)

用於生成、解析和驗證JWT。

@Service
@Slf4j
public class JwtService {

    //預設Token過期時間
    private Long EXPIRATION_TIME = Long.valueOf(360000000);

    //密鑰
    private String SECRET_KEY ="BZDuw8k4sHCFTHVtAhUt2B7n657FHUHx2DQfVTcPpxD3yqGBwXSnD2enURrYXsQN";

    /**
     * 從JWT令牌中提取使用者名稱
     */
    public String extractUsername(String token) {
        //從JWT取得Subject聲明值
        return extractClaim(token, Claims::getSubject);
    }

    /**
     * 從JWT令牌中提取過期時間
     */
    public Date extractExpiration(String token) {
        //從JWT取得Expiration聲明值。
        return extractClaim(token, Claims::getExpiration);
    }

    /**
     * 從JWT令牌中提取聲明,接受claimsResolver函數,此函數用於解析JWT的聲明。
     */
    public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
        //用來解析JWT令牌中的所有聲明。
        final Claims claims = extractAllClaims(token);
        return claimsResolver.apply(claims);
    }

    /**
     * 使用簽名密鑰解析JWT令牌中的所有聲明,並返回Claims對象
     */
    private Claims extractAllClaims(String token) {
        return Jwts
                .parserBuilder()
                .setSigningKey(createHmacSigningKeyFromSecret())
                .build()
                .parseClaimsJws(token)
                .getBody();
    }

    /**
     *  生成JWT令牌
     */
    public String generateToken(UserDetails userDetails) {
        Map<String, Object> extractClaims = new HashMap<>();
        return createToken(extractClaims, userDetails.getUsername());
    }

    /**
     * 用於設置JWT內部的聲明,並使用簽名密鑰進行簽名
     */
    private String createToken(Map<String, Object> claims, String subject) {
        return Jwts.builder()
                .setClaims(claims)
                .setSubject(subject)
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
                .signWith(createHmacSigningKeyFromSecret(), SignatureAlgorithm.HS256)
                .compact();
    }

    /**
     * 從JWT令牌中提取過期時間與當前時間比較是否已經過期。
     */
    private Boolean isTokenExpired(String token) {
        final Date expirationDate = extractExpiration(token);
        return expirationDate.before(new Date());
    }

    /**
     * 從JWT令牌中提取使用者名稱,並呼叫isTokenExpired確保令牌未過期
     */
    public Boolean validateToken(String token, UserDetails userDetails) {
        final String username = extractUsername(token);
        return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
    }

    /**
     * 獲取用於簽署JWT令牌的密鑰
     */
    private Key createHmacSigningKeyFromSecret() {
        // 從SECRET_KEY獲取Base64編碼的密鑰位元組數組
        byte[] keyBytes = Decoders.BASE64.decode(SECRET_KEY);
        // 使用Keys.hmacShaKeyFor 創建用於 HMAC 簽名的密鑰對象
        return Keys.hmacShaKeyFor(keyBytes);
    }
}

上一篇
開發學習之旅 Day13 - 使用Spring security保護Java應用程序
下一篇
開發學習之旅 Day15 - 使用 JSON Web Token 進行身份驗證(二)
系列文
Android與Spring Boot開發學習之旅30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言