前后端协同作战:Java实现Token无感刷新全流程

在Java应用中实现无感Token刷新的核心原理是:当Access Token过期时,通过Refresh Token自动获取新Token并重试请求,用户全程无感知。以下是详细实现方案:


核心原理

  1. 双Token机制

    • Access Token:短期有效(如2小时),用于请求鉴权

    • Refresh Token:长期有效(如7天),用于刷新Access Token

  2. 无感刷新流程

    • 请求接口返回401/403时触发Token刷新

    • 用Refresh Token获取新Access Token

    • 自动重试原始请求

    • 若Refresh Token过期则强制退出登录


Java实现(基于Spring Boot + JWT)

1. 添加依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.5</version>
</dependency>
2. JWT工具类
public class JwtUtils {
    private static final String SECRET_KEY = "your-secret-key";
    private static final long ACCESS_EXPIRE = 30 * 60 * 1000; // 30分钟
    private static final long REFRESH_EXPIRE = 7 * 24 * 60 * 60 * 1000; // 7天

    // 生成双Token
    public static Map<String, String> generateTokens(String username) {
        String accessToken = Jwts.builder()
                .setSubject(username)
                .setExpiration(new Date(System.currentTimeMillis() + ACCESS_EXPIRE))
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();

        String refreshToken = Jwts.builder()
                .setSubject(username)
                .setExpiration(new Date(System.currentTimeMillis() + REFRESH_EXPIRE))
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();

        return Map.of("accessToken", accessToken, "refreshToken", refreshToken);
    }

    // 刷新Access Token
    public static String refreshAccessToken(String refreshToken) throws ExpiredJwtException {
        Claims claims = parseToken(refreshToken);
        return Jwts.builder()
                .setSubject(claims.getSubject())
                .setExpiration(new Date(System.currentTimeMillis() + ACCESS_EXPIRE))
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();
    }

    // 解析Token
    public static Claims parseToken(String token) {
        return Jwts.parser()
                .setSigningKey(SECRET_KEY)
                .parseClaimsJws(token)
                .getBody();
    }
}
3. 实现拦截器处理无感刷新
@Component
public class TokenRefreshInterceptor implements HandlerInterceptor {
    @Autowired
    private UserService userService; // 包含刷新Token的业务方法

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String accessToken = request.getHeader("Authorization");
        try {
            JwtUtils.parseToken(accessToken); // 验证Access Token
            return true;
        } catch (ExpiredJwtException ex) {
            // Access Token过期时尝试刷新
            String refreshToken = request.getHeader("Refresh-Token");
            if (refreshToken != null) {
                try {
                    // 刷新Token并更新响应头
                    String newAccessToken = userService.refreshToken(refreshToken);
                    response.setHeader("New-Access-Token", newAccessToken);
                    return true;
                } catch (Exception e) {
                    response.setStatus(HttpStatus.UNAUTHORIZED.value());
                    return false; // 刷新失败
                }
            }
        }
        return false;
    }
}
4. 前端配合实现自动重试
// 使用axios拦截器
axios.interceptors.response.use(
  response => response,
  async error => {
    const originalRequest = error.config;
    if (error.response.status === 401 && !originalRequest._retry) {
      originalRequest._retry = true;
      
      // 用Refresh Token获取新Access Token
      const newToken = await refreshToken(); 
      
      // 更新请求头并重试
      originalRequest.headers['Authorization'] = `Bearer ${newToken}`;
      return axios(originalRequest);
    }
    return Promise.reject(error);
  }
);

关键注意事项

  1. 安全存储

    • Refresh Token必须存储在HttpOnly Cookie中,防止XSS攻击

    • Access Token建议存内存或SessionStorage

  2. 并发控制

    • 当多个请求同时触发刷新时,需用锁机制保证只刷新一次

  3. Refresh Token轮换

    • 每次刷新后生成新的Refresh Token,使旧Token立即失效

  4. 失效处理

    • Refresh Token过期需清空客户端Token并跳转登录页


流程示意图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值