Spring Boot中的JWT Token自动续期

引言

在现代Web应用程序中,JSON Web Tokens(JWT)被广泛用于身份验证和授权。由于JWT是无状态的,它在生成后通常会有一个固定的有效期限。为了提升用户体验,应用程序通常需要实现JWT token的自动续期功能。本文将介绍如何在Spring Boot中实现JWT token的自动续期。

JWT的基本原理

JWT是一种开放标准(RFC 7519),用于在网络应用环境间以JSON对象安全地传递信息。JWT是由三部分组成的字符串,以.分隔:头部、载荷和签名。

  • 头部(Header):一般由令牌的类型(JWT)和签名算法(如HS256)组成。
  • 载荷(Payload):包含声明(Claims),一些是注册声明,包含用户信息。
  • 签名(Signature):为了验证JWT的发送者是他所声称的,并确保消息在传输过程中没有被篡改。

实现JWT自动续期

在我们的实现中,用户每次请求都会验证Token的有效性。如果Token接近过期或者已经过期,我们将返回一个新的Token。具体步骤如下:

  1. 创建Token:用户成功登录后生成JWT。
  2. 验证Token:每次请求时校验token的有效性。
  3. 续期Token:在必要时(例如Token即将过期)生成新的Token。

下面是JWT token的生成和续期的代码示例。

1. Maven依赖配置

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

2. JWT工具类

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Component
public class JwtUtil {
    private final String SECRET_KEY = "mySecretKey";
    private final long EXPIRATION_TIME = 1000 * 60 * 15; // 15分钟

    public String generateToken(String username) {
        Map<String, Object> claims = new HashMap<>();
        return createToken(claims, username);
    }

    private String createToken(Map<String, Object> claims, String subject) {
        return Jwts.builder()
                .setClaims(claims)
                .setSubject(subject)
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();
    }

    public boolean validateToken(String token, String username) {
        final String extractedUsername = extractUsername(token);
        return (extractedUsername.equals(username) && !isTokenExpired(token));
    }

    public String extractUsername(String token) {
        return extractAllClaims(token).getSubject();
    }

    private Claims extractAllClaims(String token) {
        return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
    }

    private boolean isTokenExpired(String token) {
        return extractAllClaims(token).getExpiration().before(new Date());
    }

    public String refreshToken(String token) {
        if (isTokenExpired(token)) {
            return null; // Token已经过期,无法续期
        }
        String username = extractUsername(token);
        return generateToken(username); // 生成新的Token
    }
}

3. 续期逻辑示例

@RestController
@RequestMapping("/api")
public class AuthController {

    @Autowired
    private JwtUtil jwtUtil;

    @PostMapping("/login")
    public ResponseEntity<String> login(@RequestBody AuthRequest authRequest) {
        // 这里省略用户身份验证逻辑
        String token = jwtUtil.generateToken(authRequest.getUsername());
        return ResponseEntity.ok(token);
    }

    @GetMapping("/refresh-token")
    public ResponseEntity<String> refreshToken(@RequestHeader("Authorization") String token) {
        String newToken = jwtUtil.refreshToken(token.replace("Bearer ", ""));
        if (newToken == null) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Token已经过期,无法续期");
        }
        return ResponseEntity.ok(newToken);
    }
}

4. 状态图

接下来,我们用状态图展示JWT Token的生命周期:

stateDiagram
    [*] --> Token生成
    Token生成 --> Token有效
    Token有效 --> Token检查
    Token检查 --> Token续期 : Token接近过期
    Token检查 --> Token无效 : Token过期
    Token续期 --> Token有效
    Token无效 --> [*]

结尾

本文介绍了如何在Spring Boot中实现JWT token的自动续期功能。通过设计合适的JWT工具类,我们能够在用户的Token快要过期时主动进行续期,以提升用户的使用体验。同时,应用程序在实现安全功能时,也需要关注Token的生命周期管理。希望本文对您在使用JWT进行身份验证时有所帮助!