SpringBoot整合JWT實(shí)現(xiàn)Token認(rèn)證與自動刷新
Session 方式在分布式環(huán)境下不好用,JWT(JSON Web Token)是目前主流的無狀態(tài)認(rèn)證方案。服務(wù)端不需要存 Session,Token 中包含了用戶信息。
一、JWT 結(jié)構(gòu)
header.payload.signature header: 加密算法 payload: 用戶數(shù)據(jù)(不要放密碼) signature: 簽名,防止篡改
二、JWT 工具類
@Component
public class JwtUtil {
@Value("${jwt.secret:mySecretKey}")
private String secret;
@Value("${jwt.expire:86400000}")
private long expire; // 默認(rèn)24小時(shí)
public String generateToken(Long userId, String username) {
Date now = new Date();
return Jwts.builder()
.setSubject(userId.toString())
.claim("username", username)
.setIssuedAt(now)
.setExpiration(new Date(now.getTime() + expire))
.signWith(SignatureAlgorithm.HS256, secret)
.compact();
}
public Claims parseToken(String token) {
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
}
public boolean validateToken(String token) {
try {
parseToken(token);
return true;
} catch (Exception e) {
return false;
}
}
}
三、登錄接口
@RestController
@RequestMapping("/auth")
public class AuthController {
@Autowired
private JwtUtil jwtUtil;
@PostMapping("/login")
public ResultVO<Map<String, Object>> login(
@RequestParam String username,
@RequestParam String password) {
// 校驗(yàn)用戶名密碼
if (!"admin".equals(username) || !"123456".equals(password)) {
return ResultVO.error(401, "用戶名或密碼錯誤");
}
// 生成 Token
String accessToken = jwtUtil.generateToken(1001L, username);
String refreshToken = jwtUtil.generateRefreshToken(1001L);
Map<String, Object> result = new HashMap<>();
result.put("accessToken", accessToken);
result.put("refreshToken", refreshToken);
result.put("expiresIn", 86400);
return ResultVO.success(result);
}
}
四、Token 刷新
@PostMapping("/refresh")
public ResultVO<Map<String, Object>> refresh(
@RequestParam String refreshToken) {
if (!jwtUtil.validateToken(refreshToken)) {
return ResultVO.error(401, "RefreshToken 無效");
}
Claims claims = jwtUtil.parseToken(refreshToken);
Long userId = Long.parseLong(claims.getSubject());
String username = claims.get("username", String.class);
String newAccessToken = jwtUtil.generateToken(userId, username);
String newRefreshToken = jwtUtil.generateRefreshToken(userId);
return ResultVO.success(Map.of(
"accessToken", newAccessToken,
"refreshToken", newRefreshToken
));
}
五、攔截器校驗(yàn)
@Component
public class JwtInterceptor implements HandlerInterceptor {
@Autowired
private JwtUtil jwtUtil;
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
String token = request.getHeader("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
throw new BusinessException(401, "未登錄");
}
token = token.substring(7);
if (!jwtUtil.validateToken(token)) {
throw new BusinessException(401, "Token 已過期");
}
// 將用戶信息存入請求上下文
Claims claims = jwtUtil.parseToken(token);
request.setAttribute("userId", claims.getSubject());
request.setAttribute("username", claims.get("username"));
return true;
}
}
六、前端調(diào)用
// 登錄
const resp = await fetch('/auth/login', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({username: 'admin', password: '123456'})
});
const { accessToken, refreshToken } = await resp.json();
// 后續(xù)請求攜帶 Token
fetch('/api/user', {
headers: {'Authorization': 'Bearer ' + accessToken}
});
// Token 過期時(shí)用 refreshToken 刷新
async function refreshAccessToken() {
const resp = await fetch('/auth/refresh', {
method: 'POST',
body: new URLSearchParams({refreshToken})
});
const data = await resp.json();
accessToken = data.accessToken;
}
七、安全注意事項(xiàng)
// 1. JWT 中不要放敏感信息
Claims claims = Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
String password = claims.get("password"); // ? 錯誤!
// 2. 密鑰不要寫死,用配置中心或環(huán)境變量
@Value("${jwt.secret}")
private String secret;
// 3. accessToken 有效期短(15-30分鐘)
// refreshToken 有效期長(7天),專門用來刷新 accessToken
總結(jié)
Session 認(rèn)證:服務(wù)端存 Session,分布式下需要共享 Session JWT 認(rèn)證: 無狀態(tài),Token 攜帶用戶信息,適合分布式 JWT 缺點(diǎn):簽發(fā)后無法主動失效(只能等過期) 解決方案:accessToken 短時(shí)效 + refreshToken 刷新機(jī)制
到此這篇關(guān)于SpringBoot整合JWT實(shí)現(xiàn)Token認(rèn)證與自動刷新的文章就介紹到這了,更多相關(guān)SpringBoot Token認(rèn)證與自動刷新內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java中的Cookie和Session詳細(xì)解析
- Java如何獲取Cookie和Session
- 幾句話說清session,cookie和token的區(qū)別及說明
- Java cookie和session會話技術(shù)介紹
- java實(shí)現(xiàn)認(rèn)證與授權(quán)的jwt與token+redis,哪種方案更好用?
- JWT概述以及Token刷新機(jī)制詳解
- Java如何使用JWT實(shí)現(xiàn)Token認(rèn)證機(jī)制
- springBoot整合jwt實(shí)現(xiàn)token令牌認(rèn)證的示例代碼
- Java開發(fā)日記:Cookie、Session、Token和JWT的工作原理和適用場景
相關(guān)文章
mybatis-plus的多租戶不同版本實(shí)現(xiàn)的兩種方式
本文主要介紹了mybatis-plus的多租戶不同版本實(shí)現(xiàn)的兩種方式,Mybatis Plus 3.4.0版本之后多租戶的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2025-03-03
深層剖析java應(yīng)用開發(fā)中MyBayis緩存
這篇文章主要為大家深層剖析java開發(fā)中MyBayis緩存,文中講解了Mybatis緩存的分類以及使用的方式,有需要的朋友可以借鑒參考下,希望可以有所幫助2021-09-09
Springboot整合第三方登錄功能的實(shí)現(xiàn)示例
本文主要介紹了Springboot整合第三方登錄功能的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01
阿里資深技術(shù)專家:在各階段中3年經(jīng)驗(yàn)的java程序員應(yīng)該具備哪些技術(shù)能力
這篇文章主要介紹了阿里資深技術(shù)專家:在各階段中3年經(jīng)驗(yàn)的java程序員應(yīng)該具備哪些技術(shù)能力,本文給大家列舉了一些內(nèi)容,大家可以根據(jù)自己需要有方法的掌握,感興趣的朋友跟隨小編一起看看吧2020-07-07
Spring Boot中使用Spring-data-jpa的配置方法詳解
今天小編就為大家分享一篇關(guān)于Spring Boot中使用Spring-data-jpa的配置方法詳解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-03-03
Java二分查找算法實(shí)現(xiàn)代碼實(shí)例
這篇文章主要介紹了Java二分查找算法實(shí)現(xiàn)代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11

