iT邦幫忙

2023 iThome 鐵人賽

DAY 21
0

第21天,前幾日介紹了建立API使用MyBatis實現CRUD,順帶解釋攔截器與過濾器的設計,WebAPI多少會出現需要受保護的請求,此時需要進行身分認證比較常見的作法是使用帳號密碼登入,並取得相關登入授權認證資料

實現的流程是客戶端發送請求時,會將授權資料夾在請求中,若客戶端向受保護的端點發送請求,會根據這筆資料進行相關身分驗證,確保當前請求擁有合法身分,才能執行當前端點的核心邏輯,今天先來介紹以JWT產生授權資料的實作

JWT(Json Web Token)

說到登入授權不得不提JWT,這是基於RFC 7519訂定的標準,本質就是「特定結構組成的字串」,主要結構包含三大部分
tips: 可以善用 https://jwt.io 來看JWT的內容

  • Header: 主要記錄了字串加密的演算法,以及Token類型
  • Payload: 主要存放使用者相關資訊,和JWT的可使用時間及到期日,由於是JSON序列化後的字串,伺服器可以透過反序列化,取得相關資料,進行相應邏輯操作
  • Signature: 用來驗證Token未被串改的安全碼

安裝 JWT 依賴項目

第一步: 配置依賴項目

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

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

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

打造JWT授權API

首先打開 application.properites

// 設定安全秘鑰
jwt.secret="MaldbaPecC+am/rNCs1LIQTbJXk+a+LFzam/rNCs1LIQTbJXk+a+LFzk+SbqxmutJeFArJCi3b2p/pSsFArJCi3b2p/pSsFArJCi3b2p/pSsFArJCi3b2p/pSs"

// 設定逾期時間,注意單位是毫秒必須乘上1000才是逾期秒數
jwt.expire_time=60000

打開 API Controller 先注入JWT預設設定到類別屬性

@Value("${jwt.expire_time}")
private int jwtExpTime;

@Value("${jwt.secret}")
private String jwtSecret;

按照JWT使用規範,建立一個方法,照規範取得加密金鑰,寫入指定JWT物件

/**
 * 將 密鑰 轉換成 Key物件
*/
private SecretKey jwtGenerateKey() {
    byte[] encodeKey = jwtSecret.getBytes();
    return Keys.hmacShaKeyFor(encodeKey);
}

用JWT套件實作授權API

/**
 * 授權JWT字串
 */
@GetMapping("/jwt/generate")
public Map<String, Object> authJwt() {
    // 自定義資料
    Map<String, Object> claims = new HashMap<>();
    claims.put("language", "java");

    // JWT識別ID(此處用UUID)
    Date expireDate = new Date(System.currentTimeMillis() + jwtExpTime);
    String identityId = UUID.randomUUID().toString();

    // 利用建造者建構JWT字串
    String jwtToken = Jwts.builder().setClaims(claims)
            .setSubject("I Love Java").setId(identityId)
            .setIssuedAt(new Date(System.currentTimeMillis()))
            .setExpiration(expireDate)
            .signWith(jwtGenerateKey(), SignatureAlgorithm.HS256)
            .compact();

    Map<String, Object> response = new HashMap<>();
    response.put("token", jwtToken);
    return response;
}

透過 Postman呼叫API可以成功取得JWT Token

https://ithelp.ithome.com.tw/upload/images/20231004/20161920TGVcKdVj0H.png

將Token字串放到 jwt.io查看資訊

https://ithelp.ithome.com.tw/upload/images/20231004/20161920RD7liwEMnV.png

PAYLOAD中除了自定義的 language 欄位外,有幾個重要的資料欄位,下面來一一介紹

  • sub: 識別JWT使用者的唯一ID
  • jti: 針對JWT字串的識別ID,主要用於防止重複使用或註銷
  • iat: JWT Token的建立時間
  • exp: Token的到期時間,超過就無法使用

產生JWT的需求完成了,但把產生JWT的邏輯寫在控制器內,違反了單一職責原則,明日來重構既有程式,並實現JWT驗證流程,除了上列欄位也能視實際情況自行添加欄位資料


上一篇
第20日 介紹攔截器與過濾器
下一篇
第22日 封裝Jwt工具類
系列文
掌握Java神器,駕馭SpringBoot猛獸30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言