第21天,前幾日介紹了建立API使用MyBatis實現CRUD,順帶解釋攔截器與過濾器的設計,WebAPI多少會出現需要受保護的請求,此時需要進行身分認證比較常見的作法是使用帳號密碼登入,並取得相關登入授權認證資料
實現的流程是客戶端發送請求時,會將授權資料夾在請求中,若客戶端向受保護的端點發送請求,會根據這筆資料進行相關身分驗證,確保當前請求擁有合法身分,才能執行當前端點的核心邏輯,今天先來介紹以JWT產生授權資料的實作
說到登入授權不得不提JWT,這是基於RFC 7519訂定的標準,本質就是「特定結構組成的字串」,主要結構包含三大部分
tips: 可以善用 https://jwt.io 來看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>
首先打開 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
將Token字串放到 jwt.io查看資訊
PAYLOAD中除了自定義的 language 欄位外,有幾個重要的資料欄位,下面來一一介紹
產生JWT的需求完成了,但把產生JWT的邏輯寫在控制器內,違反了單一職責原則,明日來重構既有程式,並實現JWT驗證流程,除了上列欄位也能視實際情況自行添加欄位資料