通過筆者前兩篇文章的說明,相信大家已經知道JWT是什么,怎么用,該如何結合Spring Security使用。那么本節就用代碼來具體的實現一下JWT登錄認證及鑒權的流程。
一、環境準備工作
建立Spring Boot項目并集成了Spring Security,項目可以正常啟動 通過controller寫一個HTTP的GET方法服務接口,比如:“/hello” 實現最基本的動態數據驗證及權限分配,即實現UserDetailsService接口和UserDetails接口。這兩個接口都是向Spring Security提供用戶、角色、權限等校驗信息的接口 如果你學習過Spring Security的formLogin登錄模式,請將HttpSecurity配置中的formLogin()配置段全部去掉。因為JWT完全使用JSON接口,沒有from表單提交。 HttpSecurity配置中一定要加上csrf().disable()
,即暫時關掉跨站攻擊CSRF的防御。這樣是不安全的,我們后續章節再做處理。以上的內容,我們在之前的文章中都已經講過。如果仍然不熟悉,可以翻看本號之前的文章。
## 二、開發JWT工具類
通過maven坐標引入JWT工具包jjwt
<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.0</version></dependency>
在application.yml中加入如下自定義一些關于JWT的配置
jwt: header: JWTHeaderName secret: aabbccdd expiration: 3600000其中header是攜帶JWT令牌的HTTP的Header的名稱。雖然我這里叫做JWTHeaderName,但是在實際生產中可讀性越差越安全。 secret是用來為JWT基礎信息加密和解密的密鑰。雖然我在這里在配置文件寫死了,但是在實際生產中通常不直接寫在配置文件里面。而是通過應用的啟動參數傳遞,并且需要定期修改。 expiration是JWT令牌的有效時間。
寫一個Spring Boot配置自動加載的工具類。
@Data@ConfigurationProperties(prefix = "jwt") //配置自動加載,prefix是配置的前綴@Componentpublic class JwtTokenUtil implements Serializable { private String secret; private Long expiration; private String header; /** * 生成token令牌 * * @param userDetails 用戶 * @return 令token牌 */ public String generateToken(UserDetails userDetails) { Map<String, Object> claims = new HashMap<>(2); claims.put("sub", userDetails.getUsername()); claims.put("created", new Date()); return generateToken(claims); } /** * 從令牌中獲取用戶名 * * @param token 令牌 * @return 用戶名 */ public String getUsernameFromToken(String token) { String username; try { Claims claims = getClaimsFromToken(token); username = claims.getSubject(); } catch (Exception e) { username = null; } return username; } /** * 判斷令牌是否過期 * * @param token 令牌 * @return 是否過期 */ public Boolean isTokenExpired(String token) { try { Claims claims = getClaimsFromToken(token); Date expiration = claims.getExpiration(); return expiration.before(new Date()); } catch (Exception e) { return false; } } /** * 刷新令牌 * * @param token 原令牌 * @return 新令牌 */ public String refreshToken(String token) { String refreshedToken; try { Claims claims = getClaimsFromToken(token); claims.put("created", new Date()); refreshedToken = generateToken(claims); } catch (Exception e) { refreshedToken = null; } return refreshedToken; } /** * 驗證令牌 * * @param token 令牌 * @param userDetails 用戶 * @return 是否有效 */ public Boolean validateToken(String token, UserDetails userDetails) { SysUser user = (SysUser) userDetails; String username = getUsernameFromToken(token); return (username.equals(user.getUsername()) && !isTokenExpired(token)); } /** * 從claims生成令牌,如果看不懂就看誰調用它 * * @param claims 數據聲明 * @return 令牌 */ private String generateToken(Map<String, Object> claims) { Date expirationDate = new Date(System.currentTimeMillis() + expiration); return Jwts.builder().setClaims(claims) .setExpiration(expirationDate) .signWith(SignatureAlgorithm.HS512, secret) .compact(); } /** * 從令牌中獲取數據聲明,如果看不懂就看誰調用它 * * @param token 令牌 * @return 數據聲明 */ private Claims getClaimsFromToken(String token) { Claims claims; try { claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody(); } catch (Exception e) { claims = null; } return claims; }}
新聞熱點
疑難解答