JWT 是前后端分离项目里非常常见的登录鉴权方案。本文从用户登录、签发 Token、请求携带 Token、后端解析 Token、权限控制和过期处理讲起,适合 Python 后端初学者和秋招面试复习。

【一、认证和授权先区分清楚】

很多人学 JWT 时会把认证和授权混在一起。

- 认证 Authentication:确认你是谁。比如登录时校验账号密码。

- 授权 Authorization:确认你能做什么。比如普通用户不能访问管理员接口。

登录成功只能说明你是某个用户,不代表你有所有权限。

【二、JWT 是什么】

JWT 全称 JSON Web Token,是一种把用户身份信息编码到 Token 里的格式。

一个 JWT 通常长这样:

xxxxx.yyyyy.zzzzz

它由三部分组成:

Header.Payload.Signature

- Header:说明算法和 token 类型。

- Payload:保存用户信息和过期时间等声明。

- Signature:签名,用来防止 token 被篡改。

注意:JWT 默认只是 Base64Url 编码,不是加密。Payload 里的内容不要放密码、身份证、手机号等敏感信息。

【三、JWT 登录流程】

典型流程:

1. 用户提交账号密码

2. 后端校验账号密码

3. 校验成功后生成 JWT

4. 前端保存 JWT

5. 前端后续请求在 Authorization 请求头携带 JWT

6. 后端验证 JWT 签名和过期时间

7. 验证通过后识别当前用户

请求头一般这样写:

http

Authorization: Bearer eyJhbGciOi...

`Bearer` 表示这是一种令牌认证方式。

【四、JWT 里面一般放什么】

Payload 常见字段:

{

  "sub": "1001",

  "username": "tom",

  "role": "admin",

  "exp": 1790000000

}

说明:

- `sub`:subject,通常放用户 id。

- `username`:用户名,非敏感信息。

- `role`:角色,可以放,但权限复杂时不建议只依赖它。

- `exp`:过期时间。

不要放:

- 密码

- 密码 hash

- 身份证

- 手机号

- API Key

- 大段业务数据

【五、JWT 和 Session 的区别】

| 对比 | Session | JWT |

|---|---|---|

| 登录状态存在哪里 | 服务端 | 客户端保存 Token |

| 服务端是否需要查会话 | 通常需要 | 通常不需要 |

| 适合场景 | 传统 Web | 前后端分离、移动端、微服务 |

| 主动失效 | 容易 | 相对麻烦 |

| 扩展性 | 依赖共享 session | 更容易跨服务 |

JWT 的优势是无状态,但无状态也意味着服务端不保存 token 状态。要想主动踢下线、修改密码后失效旧 token,通常需要引入黑名单、版本号、短 token + refresh token 等机制。

【六、FastAPI 示例】

示例只演示核心思想,真实项目要使用成熟库,例如 `python-jose` 或 `PyJWT`。

from fastapi import FastAPI, Header, HTTPException

app = FastAPI()

fake_token_user = {

    "valid-token": {"id": 1, "username": "tom", "role": "user"}

}

@app.post("/login")

def login(username: str, password: str):

    if username == "tom" and password == "123456":

        return {"access_token": "valid-token", "token_type": "bearer"}

    raise HTTPException(status_code=401, detail="用户名或密码错误")

@app.get("/me")

def me(authorization: str = Header(default="")):

    if not authorization.startswith("Bearer "):

        raise HTTPException(status_code=401, detail="未登录")

    token = authorization.replace("Bearer ", "")

    user = fake_token_user.get(token)

    if not user:

        raise HTTPException(status_code=401, detail="token 无效")

    return user

真实项目里不要用固定字符串 token,要使用签名算法生成 JWT。

【七、Access Token 和 Refresh Token】

更规范的登录系统通常会拆成两个 token:

- Access Token:有效期短,比如 30 分钟,用来访问接口。

- Refresh Token:有效期长,比如 7 天或 30 天,用来刷新 Access Token。

这样做的好处是:即使 Access Token 泄露,风险时间也比较短。

【八、权限控制怎么做】

认证通过后,还要判断权限。

例子:

普通用户:只能看自己的订单

管理员:可以看所有订单

作者:可以编辑自己的文章

超级管理员:可以管理角色和权限

项目里常见模型:

- 用户 user

- 角色 role

- 权限 permission

- 用户角色关系 user_role

- 角色权限关系 role_permission

简单项目可以先用角色控制,复杂项目再做 RBAC。

【九、常见安全问题】

- JWT secret 太短,容易被爆破。

- token 永不过期。

- 把敏感数据放进 payload。

- 前端把 token 存在不安全位置,又没有配合 XSS 防护。

- 后端只解析 token,不校验签名。

- 修改密码后旧 token 仍然可用。

更多推荐