基于 FastAPI 的 JWT 鉴权实战:从原理到代码,新手也能直接跑
本文介绍了JWT(JSON Web Token)在FastAPI中的实现方法。主要内容包括:1) JWT基本概念和工作原理,作为无状态认证机制;2) 完整的代码实现,包含JWT工具封装(生成、验证Token)、登录接口和需要认证的接口示例;3) 详细的使用流程说明,从登录获取Token到携带Token访问受保护接口;4) JWT的三段式结构解析(Header、Payload、Signature);
一、概念全部串起来
- HTTP 无状态:服务器不记得你是谁,每次请求都是全新的
- 登录:前端传账号密码,后端验证正确
- JWT:后端根据用户信息加密生成的一串长字符串(Token)
- 作用:当作用户的临时身份证
- 流程
前端登录 → 后端返回JWT Token 前端每次请求需要权限的接口 → 请求头带上Token 后端拦截验证Token → 有效就放行,无效/过期直接报错401
二、完整全套代码
先安装依赖
pip install pyjwt python-multipart fastapi uvicorn
1、完整 JWT 工具封装(生成 Token、解析 Token、异常处理)
单独写好通用工具,所有接口都能用
import jwt
from datetime import datetime, timedelta
from fastapi import Depends, HTTPException, Header
# ===================== JWT 基础配置 =====================
# 密钥(非常重要!!自己随便改一串复杂字符串,绝对不能泄露给别人)
SECRET_KEY = "my_private_secret_key_123456789_abcdef"
# 加密算法
ALGORITHM = "HS256"
# Token过期时间:7天
ACCESS_TOKEN_EXPIRE_DAYS = 7
# ===================== 1. 生成Token(登录成功调用) =====================
def create_token(user_id: int, username: str):
"""
根据用户id、用户名生成JWT Token
"""
# 计算过期时间
expire_time = datetime.utcnow() + timedelta(days=ACCESS_TOKEN_EXPIRE_DAYS)
# Token里面存储的用户信息(载荷,不要放密码敏感信息)
payload = {
"user_id": user_id,
"username": username,
"exp": expire_time # 过期时间字段,jwt自带识别
}
# 加密生成token字符串
token = jwt.encode(payload, SECRET_KEY, algorithm=ALGORITHM)
return token
# ===================== 2. 验证Token(所有需要登录的接口调用) =====================
def verify_token(token: str):
"""
解析token,返回里面的用户信息
token无效、过期、篡改 全部抛出异常
"""
try:
# 解密token
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
return payload
except jwt.ExpiredSignatureError:
# Token过期
raise HTTPException(status_code=401, detail="Token已过期,请重新登录")
except jwt.PyJWTError:
# Token无效、伪造、被篡改
raise HTTPException(status_code=401, detail="Token无效,请重新登录")
# ===================== 3. 依赖项:自动校验Token(接口直接用Depends即可) =====================
async def get_current_user(Authorization: str = Header(None)):
"""
FastAPI依赖注入,所有需要登录的接口,加这个参数就自动鉴权
前端请求头格式:Authorization: Bearer 你的token字符串
"""
# 1. 判断有没有传请求头
if not Authorization:
raise HTTPException(status_code=401, detail="未登录,请携带Token")
# 2. 拆分 Bearer 和 token
# 格式:Bearer xxxxxxx
if not Authorization.startswith("Bearer "):
raise HTTPException(status_code=401, detail="Token格式错误")
# 截取真正的token字符串
token = Authorization[7:]
# 3. 验证token,返回用户信息
user_info = verify_token(token)
return user_info
2、登录接口(验证账号密码 + 返回 Token)
user_router 路由
from fastapi import APIRouter
from pydantic import BaseModel
user_router = APIRouter()
# 前端登录提交的参数模型:账号+密码
class Login(BaseModel):
username: str
password: str
@user_router.post("/login")
def login(login_data: Login):
"""
用户登录接口
1. 校验账号密码
2. 正确则生成JWT Token返回
"""
# 这里以后替换成:数据库查询账号密码
# 模拟数据库用户
db_user = {
"user_id": 1,
"username": "test",
"password": "123456"
}
# 账号密码校验
if login_data.username == db_user["username"] and login_data.password == db_user["password"]:
# 生成token
token = create_token(user_id=db_user["user_id"], username=db_user["username"])
return {
"code": 200,
"msg": "登录成功",
"token": token
}
else:
return {
"code": 400,
"msg": "账号或密码错误"
}
3、需要登录才能访问的接口(鉴权演示)
只要在参数里加 user = Depends(get_current_user)
接口就自动强制校验登录,没 Token 直接 401 报错
@user_router.get("/user/info")
def get_user_info(user = Depends(get_current_user)):
"""
需要登录才能访问的接口
自动校验Token,并且从Token里拿到当前登录用户信息
"""
# user 就是我们从token解析出来的:{"user_id":1,"username":"test"}
return {
"code": 200,
"msg": "获取用户信息成功",
"data": user
}
4、文件上传接口,加上登录权限(实战)
上传接口,加上登录校验,必须登录才能上传文件
from fastapi import UploadFile, File
from typing import List
import os
@user_router.post("/file/uploads/")
async def files_upload(
files: List[UploadFile] = File(..., alias="file"),
user = Depends(get_current_user) # 加上这一行,强制登录
):
files_name_type = []
for file in files:
files_name_type.append(file.filename + " " + file.content_type)
filename = os.path.basename(file.filename)
with open(filename, 'wb') as f:
f.write(await file.read())
return {
"filename": files_name_type,
"current_user": user # 顺便返回当前登录用户
}
三、完整流程走一遍(Request、Response 全过程)
1、第一步:调用登录接口(POST /login)
Request 请求
{
"username": "test",
"password": "123456"
}
Response 后端返回
{
"code": 200,
"msg": "登录成功",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6InRlc3QiLCJleHAiOjE3NDUyNjQwOTR9.xxxxxxxxxxxx"
}
这一长串字符串就是 JWT Token
2、第二步:访问需要登录的接口(比如获取用户信息、文件上传)
Postman 携带 Token 正确方式(重点!90% 人都错这里)
- 进入 Headers 请求头
- 新增一条
- Key:
Authorization - Value:
Bearer 复制你登录返回的token注意空格!Bearer 后面必须有一个空格
- Key:
Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.xxxxxx
三种错误情况,后端都会直接返回 401 Response
- 没带 Authorization 请求头
json
{"detail": "未登录,请携带Token"} - 格式不对,少了 Bearer
json
{"detail": "Token格式错误"} - Token 写错、过期、伪造
json
{"detail": "Token无效,请重新登录"}
Token 正确时
后端自动解析出用户 user_id、username,接口正常执行,返回数据。
四、JWT 三段结构详细拆解(彻底弄懂这个字符串)
你拿到的 Token 长这样:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6InRlc3QiLCJleHAiOjE3NDUyNjQwOTR9.abcdefghijk
由 . 分割成 3 段
- Header 头部声明加密算法
HS256 - Payload 载荷存放用户公开信息:
user_id、username、过期时间注意:这里是明文可解码,不要存密码、手机号等敏感数据
- Signature 签名用密钥加密生成的校验串作用:防止别人篡改第二段内容只要改了 payload 任意字符,签名就失效,后端直接判定 Token 无效。
五、结合之前所有知识点串总结
-
Request 请求
- 登录:请求体传
账号密码 - 鉴权:请求头 Headers 传
Authorization: Bearer Token - 文件上传:form-data 传文件
- 登录:请求体传
-
Response 响应
- 登录成功:返回
token字符串 - 鉴权成功:正常返回业务数据
- 鉴权失败:
401状态码 + 未登录 / Token 错误提示
- 登录成功:返回
-
无状态原理后端不需要数据库存 Token,所有用户信息都加密在 Token 本身里,每次请求解码即可,这就是 JWT 最大优点。
六、Postman 完整测试步骤(照着点一次就全会)
- 先调用
/user/login,拿到token - 打开需要鉴权的接口
/user/info - 切换到 Headers
- Key 填
Authorization - Value 填
Bearer 粘贴你的token - Send 发送,正常返回用户信息
- 你把 token 随便改几个字符再发,就会返回 401 无效
更多推荐
所有评论(0)