一、背景介绍

在 后台系统中,用户认证采用企业 SSO(单点登录) + JWT + 业务 Token 的多层架构。本文将详细讲解 JWT 和业务 Token 在在开发系统中的作用、关系以及具体实现方式。

二、整体架构图

text

┌─────────────────────────────────────────────────────────────────────────────┐
│                              用户登录流程                                    │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   用户        SSO中心        前端        后端        Redis                   │
│    │            │            │           │           │                     │
│    │──登录──────▶│            │           │           │                     │
│    │            │──验证──────▶│           │           │                     │
│    │            │◀─返回JWT───│           │           │                     │
│    │            │            │           │           │                     │
│    │            │            │─GET /auth/xxx?tk=JWT──▶│                    │
│    │            │            │           │           │                     │
│    │            │            │           │─解析JWT────▶│                     │
│    │            │            │           │           │                     │
│    │            │            │           │─生成业务token─▶│                  │
│    │            │            │           │           │                     │
│    │            │            │           │─存储token→用户──▶│                 │
│    │            │            │           │           │                     │
│    │            │            │◀─返回业务token──│           │                     │
│    │            │            │           │           │                     │
│    │            │            │─存储到localStorage──│     │                     │
│    │            │            │           │           │                     │
└─────────────────────────────────────────────────────────────────────────────┘

三、JWT 和业务 Token 的区别

对比项 JWT (id_token) 业务 Token (APP_TOKEN)
颁发者 企业 SSO 服务器 应用后端
格式 JWT 标准格式(三段式) 随机字符串
有效期 SSO 控制(通常较短) 可配置(如 6 小时)
存储位置 前端临时使用,不持久化 localStorage + Redis
包含信息 用户身份信息(账号、邮箱等) 用户信息的 Redis Key
作用 证明"你是谁" 证明"你已登录应用"
验证方式 后端解析 JWT 获取用户信息 后端从 Redis 查 token

四、JWT 的作用与处理

4.1 JWT 从哪里来?

用户点击登录后,前端跳转到企业 SSO 登录页:

javascript

// 伪代码示例
window.location.href = `https://sso.company.com/...&redirect_uri=${redirectUri}`

登录成功后,SSO 重定向回前端,URL 中携带 id_token

text

http://localhost:xxxx/loginSSO#id_token=eyJhbGciOiJSUzI1NiIs...

4.2 前端如何提取 JWT?

javascript

// 登录回调页面
const params = window.location.href.split("#")[1];
const id_token = new URLSearchParams(params).get("id_token");

if (id_token) {
    this.userLogin();  // 调用后端接口
}

4.3 后端如何解析 JWT?

java

// JWT 解析工具类
public JSONObject parseJwtBody(String token) {
    // JWT 格式:header.payload.signature
    String[] split = token.split("\\.");
    Decoder decoder = Base64.getDecoder();
    String body = new String(decoder.decode(split[1]));
    return JSON.parseObject(body);
}

4.4 从 JWT 中提取用户信息

java

// 登录接口
JSONObject jwtJson = jwtUtil.parseJwtBody(jwtToken);
String preferredUsername = jwtJson.getString("preferred_username");
// 例如:zhangsan@company.com

// 提取用户账号
String account = preferredUsername.split("@")[0];

五、业务 Token 的生成与存储

5.1 生成业务 Token

java

// 生成随机字符串作为业务 token
String token = StringUtil.createToken(account);

5.2 存储到 Redis

java

// Redis 存储工具类
public static void saveUserToken(String account, String token, String userInfoJson) {
    Jedis jedis = jedisPool.getResource();
    jedis.select(0);
    // 业务 token 作为 key,用户信息 JSON 作为 value
    // 有效期可配置
    jedis.setex(token, TOKEN_EXPIRE_SECONDS, userInfoJson);
    jedis.close();
}

Redis 存储结构

Key (业务 token) Value (用户信息 JSON)
abc123xyz... {"account_id":"zhangsan","fullName":"张三","roles":[1001,1004]}

5.3 返回给前端

java

result.putData("token", token);
result.putData("user", userInfo);

六、前端如何存储和使用业务 Token

6.1 存储到 localStorage

javascript

// 登录成功回调
if (response.data.token) {
    sessionStorage.setItem("APP_TOKEN", response.data.token);
    localStorage.setItem("APP_TOKEN", response.data.token);
}
if (response.data.user) {
    let user = response.data.user;
    localStorage.setItem('APP_USER', JSON.stringify(user));
    localStorage.setItem('APP_CURRENT_USER', user.account_id);
}

6.2 请求拦截器自动添加 Token

javascript

// Axios 请求拦截器
axios.interceptors.request.use(config => {
    // 从 localStorage 获取 token
    const token = localStorage.getItem('APP_TOKEN')
    if (token) {
        // 添加到请求头
        config.headers.Authorization = token
    }
    return config
})

七、后端如何校验业务 Token

7.1 权限拦截器

java

// 权限拦截器
public boolean preHandle(HttpServletRequest request, 
                         HttpServletResponse response, 
                         Object handler) {
    // 1. 获取请求头中的 token
    String token = request.getHeader("Authorization");
    
    // 2. 从 Redis 查询 token 是否存在
    String userJson = redisUtil.get(token);
    
    if (StringUtil.isEmpty(userJson)) {
        // token 无效或已过期
        response.setStatus(401);
        return false;
    }
    
    // 3. 获取用户信息
    UserAccount account = JSON.parseObject(userJson, UserAccount.class);
    
    // 4. 检查是否有权限(如角色注解)
    if (!hasPermission(account.getRoles(), requiredRoles)) {
        response.setStatus(403);
        return false;
    }
    
    return true;
}

7.2 角色权限校验

java

@RoleCheck({1001, 1004, 1009})  // 只有这些角色能访问
@PostMapping("/add")
public WebResult add(@RequestBody JobConfig job) {
    // 业务逻辑
}

八、JWT vs 业务 Token 对比图

text

┌─────────────────────────────────────────────────────────────────┐
│                        登录时                                    │
├─────────────────────────────────────────────────────────────────┤
│  SSO中心 ──JWT──▶ 前端 ──JWT──▶ 后端                            │
│                                  │                              │
│                                  ▼                              │
│                            解析 JWT                              │
│                                  │                              │
│                                  ▼                              │
│                          生成业务 Token                          │
│                                  │                              │
│                    ┌─────────────┴─────────────┐                │
│                    ▼                           ▼                │
│              返回给前端                   存入 Redis              │
│                    │                           │                │
│                    ▼                           │                │
│           localStorage 存储                    │                │
│                    │                           │                │
└────────────────────┼───────────────────────────┼────────────────┘
                     │                           │
┌────────────────────┼───────────────────────────┼────────────────┐
│                    ▼                           │                │
│                  后续请求                       │                │
│                    │                           │                │
│             请求头带业务 Token                   │                │
│                    │                           │                │
│                    ▼                           │                │
│              后端拦截器                         │                │
│                    │                           │                │
│                    └───────────从 Redis 查询────┘                │
│                                  │                              │
│                                  ▼                              │
│                            获取用户信息                          │
│                                  │                              │
│                                  ▼                              │
│                            执行业务                              │
└─────────────────────────────────────────────────────────────────┘

九、为什么需要两层 Token?

问题 解决方案
JWT 有效期短,需要频繁刷新 业务 Token 有效期更长
JWT 无法主动失效 业务 Token 存在 Redis,可主动删除
需要存储用户权限信息 Redis 中存储完整的用户对象
分布式部署需要共享会话 Redis 统一存储,多实例共享

十、关键代码文件汇总

文件 作用
LoginSSO.vue 处理 SSO 登录回调,提取 JWT
main.js 拦截器,自动添加 token 到请求头
AuthController 解析 JWT,生成业务 token
RedisUtil.java Redis 存储业务 token
AuthInterceptor.java 拦截请求,校验 token
TokenUtil.java 生成随机业务 token

十一、总结

概念 一句话总结
JWT (id_token) SSO 中心颁发的临时身份证,证明"你是谁"
业务 Token 应用自己颁发的门禁卡,证明"你可以进"
Redis 存储业务 token 和用户信息的中间站
localStorage 前端存储业务 token 的地方
拦截器 后端校验业务 token 的关卡

核心流程

  1. 用户登录企业 SSO → 获得 JWT

  2. 前端把 JWT 交给后端

  3. 后端解析 JWT,生成业务 token

  4. 业务 token 存 Redis,同时返回给前端

  5. 前端存 localStorage,后续请求自动带上

  6. 后端拦截器从 Redis 校验 token 有效性

一句话记住:JWT 是"临时门票",业务 Token 是"长期会员卡"! 🎯

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐