在现代的Web开发中,JWT(JSON Web Token)被广泛应用于用户认证和授权。基于JWT的双token机制,即使用access_token和refresh_token的组合,能够有效地提高应用的安全性和用户体验。下面,我们将探讨如何在Spring Boot中实现这一方案。
1. 方案概述
- Access Token:短期有效的令牌,用于用户的身份验证,通常在用户登录后生成,并具有较短的过期时间(如15分钟)。
- Refresh Token:长期有效的令牌,用于获取新的access_token,通常具有较长的过期时间(如7天或更长)。
使用双token机制的好处在于,即使access_token被盗取,攻击者也只能在有效期内使用它,而refresh_token则可以通过更严格的策略来管理,从而进一步提升安全性。
2. 依赖配置
在Spring Boot项目中,首先需要添加JWT相关的依赖。可以在pom.xml
中添加如下依赖:
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
3. JWT工具类
创建一个JWT工具类,用于生成和验证token。
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class JwtUtil {
private String secretKey = "your_secret_key";
private long accessTokenValidity = 15 * 60 * 1000; // 15分钟
private long refreshTokenValidity = 7 * 24 * 60 * 60 * 1000; // 7天
public String generateAccessToken(String username) {
return generateToken(username, accessTokenValidity);
}
public String generateRefreshToken(String username) {
return generateToken(username, refreshTokenValidity);
}
private String generateToken(String username, long validity) {
long now = System.currentTimeMillis();
Date expiryDate = new Date(now + validity);
JwtBuilder builder = Jwts.builder()
.setSubject(username)
.setIssuedAt(new Date(now))
.setExpiration(expiryDate)
.signWith(SignatureAlgorithm.HS512, secretKey);
return builder.compact();
}
public Claims validateToken(String token) {
return Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(token)
.getBody();
}
}
4. 用户认证与授权
在用户登录成功后,将生成access_token和refresh_token,并将它们返回给前端。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/auth")
public class AuthController {
@Autowired
private JwtUtil jwtUtil;
@PostMapping("/login")
public ResponseEntity<Map<String, String>> login(@RequestBody LoginRequest loginRequest) {
// 验证用户身份逻辑省略
String username = loginRequest.getUsername();
String accessToken = jwtUtil.generateAccessToken(username);
String refreshToken = jwtUtil.generateRefreshToken(username);
Map<String, String> tokens = new HashMap<>();
tokens.put("access_token", accessToken);
tokens.put("refresh_token", refreshToken);
return ResponseEntity.ok(tokens);
}
}
5. 刷新token逻辑
当access_token过期时,用户可以使用refresh_token获取新的access_token。
@PostMapping("/refresh")
public ResponseEntity<Map<String, String>> refresh(@RequestBody Map<String, String> token) {
String refreshToken = token.get("refresh_token");
Claims claims = jwtUtil.validateToken(refreshToken);
// 检查refresh_token是否有效(可以添加更多逻辑)
String username = claims.getSubject();
String newAccessToken = jwtUtil.generateAccessToken(username);
Map<String, String> tokens = new HashMap<>();
tokens.put("access_token", newAccessToken);
return ResponseEntity.ok(tokens);
}
6. 总结
基于JWT的双token机制在Spring Boot中实现相对简单,但仍需注意安全性问题,比如对refresh_token的存储和验证过程。在实际应用中,可以结合数据库和缓存技术以增强令牌的安全性和有效性。通过这种认证机制,可以有效地保护用户的敏感信息,提高用户的登录体验。