双 Token 机制的原理

双 Token 验证机制是一种用于优化用户登录体验和增强安全性的方案,通过 Access TokenRefresh Token 的组合来解决单 Token 机制中过期时间设置的矛盾问题。以下是双 Token 验证机制的总结:


一、双 Token 机制的核心思想

1. Access Token

  • 作用:用于访问受保护的资源,携带用户信息和权限。
  • 特点
    • 过期时间较短(如 30 分钟)。
    • 每次请求都需要携带。
    • 过期后需要重新获取。

2. Refresh Token

  • 作用:用于获取新的 Access Token。
  • 特点
    • 过期时间较长(如 7 天)。
    • 不携带用户信息,仅用于刷新 Access Token。
    • 存储在安全的地方(如 HttpOnly Cookie)。

二、双 Token 的工作流程

1. 用户登录

  • 用户提交账号密码,服务端验证成功后生成 Access TokenRefresh Token,并返回给客户端。

2. 请求受保护资源

  • 客户端在请求头中携带 Access Token(如 Authorization: Bearer )。
  • 服务端验证 Access Token
    • 如果有效,处理请求并返回数据。
    • 如果过期,返回错误码(如 409),提示客户端刷新 Token。

3. 刷新 Access Token

  • 客户端检测到 Access Token 过期后,使用 Refresh Token 请求新的 Token。
  • 服务端验证 Refresh Token
    • 如果有效,生成新的 Access TokenRefresh Token,并返回给客户端。
    • 如果过期,返回错误码(如 409),提示用户重新登录。

4. 用户重新登录

  • 如果 Refresh Token 也过期,客户端提示用户重新输入账号密码登录。

三、双 Token 的优势

  1. 安全性
    • Access Token 过期时间短,减少泄露风险。
    • Refresh Token 存储在安全的地方(如 HttpOnly Cookie),避免被恶意脚本窃取。
  1. 用户体验
    • 用户无需频繁登录,通过 Refresh Token 自动刷新 Access Token
  1. 灵活性
    • 可以根据业务需求调整 Access TokenRefresh Token 的过期时间。

四、后端实现代码示例

以下是基于 Spring Boot 和 JJWT 的双 Token 实现示例。

1. 生成双 Token

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;

public class JwtUtil {
    private static final String SECRET_KEY = "changwu"; // 密钥
    private static final long ACCESS_TOKEN_EXPIRE = 30 * 60 * 1000; // 30分钟
    private static final long REFRESH_TOKEN_EXPIRE = 7 * 24 * 60 * 60 * 1000; // 7天

    // 生成 Access Token
    public static String createAccessToken(String userId, String username) {
        return Jwts.builder()
                .setId(userId)
                .setSubject(username)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + ACCESS_TOKEN_EXPIRE))
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();
    }

    // 生成 Refresh Token
    public static String createRefreshToken(String userId) {
        return Jwts.builder()
                .setId(userId)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + REFRESH_TOKEN_EXPIRE))
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();
    }
}

2. 验证 Token

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;

public class JwtUtil {
    // 解析 Token
    public static Claims parseToken(String token) {
        return Jwts.parser()
                .setSigningKey(SECRET_KEY)
                .parseClaimsJws(token)
                .getBody();
    }

    // 验证 Token 是否过期
    public static boolean isTokenExpired(String token) {
        Claims claims = parseToken(token);
        return claims.getExpiration().before(new Date());
    }
}

3. 刷新 Token 接口

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class AuthController {
    @PostMapping("/api/user/refreshToken")
    public ResponseEntity refreshToken(@RequestParam String refreshToken) {
        try {
            Claims claims = JwtUtil.parseToken(refreshToken);
            if (JwtUtil.isTokenExpired(refreshToken)) {
                return ResponseEntity.status(409).body("用户未登录");
            }
            String userId = claims.getId();
            String newAccessToken = JwtUtil.createAccessToken(userId, "username");
            String newRefreshToken = JwtUtil.createRefreshToken(userId);
            return ResponseEntity.ok(Map.of(
                "accessToken", newAccessToken,
                "refreshToken", newRefreshToken
            ));
        } catch (Exception e) {
            return ResponseEntity.status(409).body("用户未登录");
        }
    }
}

五、前端配合

  1. 登录成功后
    • 存储 Access TokenRefresh Token
    • 每次请求携带 Access Token
  1. 检测到 Access Token 过期
    • 使用 Refresh Token 请求新的 Token。
    • 如果 Refresh Token 也过期,提示用户重新登录。
  1. 重新登录
    • 清除本地存储的 Token。
    • 跳转到登录页面。

六、总结

双 Token 机制通过 Access TokenRefresh Token 的组合,解决了单 Token 机制中过期时间设置的矛盾问题,既保证了安全性,又提升了用户体验。实际项目中,需要前后端密切配合,确保流程的顺畅和安全。

你可能感兴趣的:(java,前端,服务器,tomcat,spring,boot,jvm,linux)