当前位置: 首页 > article >正文

Token相关设计

文章目录

    • 1. 双Token 机制概述
      • 1.1 访问令牌(Access Token)
      • 1.2 刷新令牌(Refresh Token)
    • 2. 双Token 认证流程
    • 3. Spring Boot 具体实现
      • 3.1 生成 Token(使用 JWT)
      • 3.2 解析 Token
      • 3.3 登录接口(返回双 Token)
      • 3.4 刷新 Token 接口
      • 3.5 退出登录
    • 4. 总结 🚀

在微服务架构中,Token 认证是保障系统安全性的重要手段,常见的方式包括 JWT(JSON Web Token)基于 Redis 的 Token 认证。本文将介绍 双Token 机制 及其具体实现。


1. 双Token 机制概述

1.1 访问令牌(Access Token)

  • 用途:前端每次请求携带该令牌,用于身份认证。
  • 有效期:较短(如10分钟 - 2小时)。
  • 存储方式:前端存储(如 LocalStorage、SessionStorage、HTTP Only Cookie)。
  • 信息载荷:用户 ID、权限、过期时间等。

1.2 刷新令牌(Refresh Token)

  • 用途:用于获取新的 Access Token,避免用户频繁登录。
  • 有效期:较长(如7天 - 30天)。
  • 存储方式:数据库或 Redis(不能存储在前端,防止滥用)。
  • 信息载荷:用户 ID,仅用于重新获取 Access Token。

2. 双Token 认证流程

  1. 用户登录

    • 用户提交用户名、密码。
    • 后端校验通过后,生成 Access Token(短期) 和 Refresh Token(长期)。
    • Access Token 通过 JWT 方式返回给前端
    • Refresh Token 存储到数据库或 Redis,避免前端篡改。
  2. 请求 API 资源

    • 前端在每次请求时,携带 Authorization: Bearer <Access Token>
    • 后端解析 Access Token,校验有效性。
    • 通过则返回资源,失败则根据错误码处理(如 401 Unauthorized)。
  3. Token 过期时的处理

    • Access Token 过期,但 Refresh Token 仍有效 :

      • 前端调用 刷新接口,携带 Refresh Token 请求新 Access Token。
      • 后端验证 Refresh Token 后,重新生成 Access Token 并返回。
    • Refresh Token 过期或无效:

      • 需要用户重新登录。
  4. 用户登出

    • 后端删除 Refresh Token 记录。
    • 前端删除 Access Token。

3. Spring Boot 具体实现

3.1 生成 Token(使用 JWT)

import io.jsonwebtoken.*;
import java.util.Date;

public class JwtUtil {
    private static final String SECRET_KEY = "your_secret_key";
    private static final long ACCESS_TOKEN_EXPIRATION = 2 * 60 * 60 * 1000; // 2小时
    private static final long REFRESH_TOKEN_EXPIRATION = 7 * 24 * 60 * 60 * 1000; // 7天

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

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

3.2 解析 Token

public static Claims parseToken(String token) {
    return Jwts.parser()
            .setSigningKey(SECRET_KEY)
            .parseClaimsJws(token)
            .getBody();
}

3.3 登录接口(返回双 Token)

@RestController
@RequestMapping("/auth")
public class AuthController {
    @PostMapping("/login")
    public Map<String, String> login(@RequestBody LoginRequest request) {
        // 1. 校验用户名和密码(省略)
        
        // 2. 生成 Token
        String accessToken = JwtUtil.generateAccessToken(request.getUsername());
        String refreshToken = JwtUtil.generateRefreshToken(request.getUsername());
        
        // 3. 存储 Refresh Token(示例使用 Redis)
        redisTemplate.opsForValue().set("refresh_token:" + request.getUsername(), refreshToken, 7, TimeUnit.DAYS);
        
        // 4. 返回 Token
        Map<String, String> tokens = new HashMap<>();
        tokens.put("accessToken", accessToken);
        tokens.put("refreshToken", refreshToken);
        return tokens;
    }
}

3.4 刷新 Token 接口

@PostMapping("/refresh")
public ResponseEntity<Map<String, String>> refresh(@RequestHeader("Authorization") String refreshToken) {
    // 1. 校验 Refresh Token
    Claims claims = JwtUtil.parseToken(refreshToken);
    String userId = claims.getSubject();

    // 2. 检查 Redis 是否存储该 Refresh Token
    String storedToken = redisTemplate.opsForValue().get("refresh_token:" + userId);
    if (storedToken == null || !storedToken.equals(refreshToken)) {
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
    }

    // 3. 生成新的 Access Token
    String newAccessToken = JwtUtil.generateAccessToken(userId);
    
    // 4. 返回新的 Token
    Map<String, String> tokens = new HashMap<>();
    tokens.put("accessToken", newAccessToken);
    return ResponseEntity.ok(tokens);
}

3.5 退出登录

@PostMapping("/logout")
public ResponseEntity<Void> logout(@RequestHeader("Authorization") String accessToken) {
    Claims claims = JwtUtil.parseToken(accessToken);
    String userId = claims.getSubject();
    
    // 删除 Redis 中的 Refresh Token
    redisTemplate.delete("refresh_token:" + userId);
    return ResponseEntity.ok().build();
}

4. 总结 🚀

机制作用过期时间存储位置
Access Token用于 API 认证短(10分钟-2小时)前端 LocalStorage/SessionStorage
Refresh Token用于刷新 Access Token长(7天-30天)Redis/数据库
  • 双 Token 机制 既保证了安全性(短期有效的 Access Token)又提升了用户体验(长期有效的 Refresh Token)。
  • Access Token 过期时,通过 Refresh Token 重新获取,而无需重新登录。
  • Refresh Token 需要存储在后端(如 Redis),避免前端泄露。

博客主页: 总是学不会.


http://www.kler.cn/a/572488.html

相关文章:

  • Oracle 数据库中的用户
  • SP导入智能材质球
  • 《OpenCV》—— dlib(换脸操作)
  • 洛谷 P2142 高精度减法(详解)c++
  • Spring Cloud Alibaba学习 4- Spring Cloud Gateway入门使用
  • 湖仓一体概述
  • React封装通用Table组件,支持搜索(多条件)、筛选、自动序号、数据量统计等功能。未采用二次封装调整灵活,包含使用文档
  • leetcode日记(77)子集Ⅱ
  • Apache IoTDB 树表双模型直播回顾(上)
  • pytest中pytest.ini文件的使用
  • python八皇后游戏
  • Java 第十一章 GUI编程(2)
  • 游戏引擎学习第135天
  • AI×电商数据API接口:深度融合,引领未来电商行业浪潮
  • docker默认网段和宿主机环境冲突时的处理
  • pytorch获取模型性能
  • 【GPU使用】如何在物理机和Docker中指定GPU进行推理和训练
  • 一、docker初识
  • 【在线用户监控】在线用户查询、强退用户
  • Java利用JSch进行SFTP进行SSH连接远程服务器进行目录创建与上传文件,ChannelSftp