GitHub链接:Java_Code_template/Login at main · mao-design/Java_Code_template

1. 登录时发生什么?

用户输入:

用户名:admin
密码:123456

后端验证成功。

生成两个 Token:

Access Token

例如:

AccessToken-A

里面:

{
  "username":"admin",
  "type":"access",
  "exp":"10:30"
}

有效期:

30分钟

用途:

访问接口

比如:

GET /user/info
Authorization: Bearer AccessToken-A

Refresh Token

例如:

RefreshToken-A

里面:

{
  "username":"admin",
  "type":"refresh",
  "jti":"abc123",
  "exp":"7天后"
}

有效期:

7天

用途:

换新的 Access Token

然后:

Refresh Token 存 Redis:

key:
refresh:admin:abc123


value:
RefreshToken-A

此时:

客户端:
    AccessToken-A
    RefreshToken-A


Redis:
    refresh:admin:abc123
            |
            ↓
      RefreshToken-A

2. 平时访问接口怎么办?

比如:

10:05 请求:

GET /order/list

带:

AccessToken-A

流程:

请求
 |
 ↓
JwtFilter
 |
 ↓
解析 AccessToken-A
 |
 ↓
检查:
    签名正确?
    有没有过期?
 |
 ↓
通过
 |
 ↓
Controller

注意:

这里:

不看 Refresh Token

不查 Redis

不生成新 Token

因为 Access Token 还有效。


3. Access Token什么时候更新?

重点:

Access Token 不是每次请求更新。

只有:

Access Token过期的时候更新

例如:

登录:

10:00

生成:

AccessToken-A
有效30分钟

所以:

10:30
过期

10:31 请求:

GET /user/info

带:

AccessToken-A

后端:

JwtFilter
    |
    ↓
发现 exp < 当前时间
    |
    ↓
ExpiredJwtException
    |
    ↓
返回401

返回:

{
 "code":401,
 "msg":"Token过期"
}

4. 前端收到401之后怎么办?

前端发现:

AccessToken失效

它不会让用户重新登录。

它调用:

POST /auth/refresh

携带:

{
 "refreshToken":"RefreshToken-A"
}

5. Refresh接口做什么?

后端收到:

RefreshToken-A

第一步:

验证 JWT:

jwtUtil.parseToken(refreshToken)

检查:

是不是refresh类型?
有没有过期?
签名对不对?

第二步:

查 Redis:

拿到:

refresh:admin:abc123

看看:

Redis里面是不是:

RefreshToken-A

如果:

一样:

说明:

这个RefreshToken有效

6. 刷新成功后,更新什么?

这里是重点。

刷新成功:

后端生成:

新的 Access Token:

AccessToken-B

新的 Refresh Token:

RefreshToken-B

为什么两个都生成?

因为:

Access Token旧的已经过期

必须换。

Refresh Token也换

为了安全。

这叫:

Refresh Token Rotation


此时:

旧:

AccessToken-A ❌
RefreshToken-A ❌

新:

AccessToken-B ✅
RefreshToken-B ✅

Redis:

删除:

refresh:admin:abc123

新增:

refresh:admin:def456
        |
        ↓
 RefreshToken-B

返回前端:

{
 "accessToken":"AccessToken-B",
 "refreshToken":"RefreshToken-B"
}

7. 前端收到新的Token怎么办?

替换本地:

原来:

localStorage

AccessToken-A
RefreshToken-A

改成:

AccessToken-B
RefreshToken-B

以后请求:

带:

AccessToken-B

8. 流程图

登录
 |
 |
生成
 |
 +----------------+
 |                |
 ↓                ↓
AccessToken-A     RefreshToken-A
30分钟            7天
 |
 |
访问接口
 |
 |
30分钟后
 |
 ↓
AccessToken-A过期
 |
 ↓
401
 |
 ↓
调用refresh接口
 |
 ↓
验证RefreshToken-A
 |
 ↓
Redis检查
 |
 ↓
生成
 |
 +----------------+
 |                |
 ↓                ↓
AccessToken-B     RefreshToken-B
 |
 |
删除旧RefreshToken-A
 |
 ↓
Redis保存RefreshToken-B
 |
 ↓
返回前端
 |
 ↓
替换旧Token