FastAPI 实战:从零实现一个可执行的 JWT 登录认证接口 一、前言在 Web 后端开发中登录认证几乎是每个项目都会遇到的基础功能。传统 Session 方案需要服务端保存用户状态而 JWT 更适合前后端分离项目。本文将使用 FastAPI 实现一个完整、可执行的 JWT 登录认证流程包括安装依赖编写登录接口生成 JWT Token校验 JWT Token获取当前登录用户访问需要登录才能使用的接口本文示例代码可以直接复制运行。二、JWT 是什么JWT全称 JSON Web Token是一种用于在客户端和服务端之间安全传递身份信息的 Token 格式。一个 JWT 通常由三部分组成Header.Payload.Signature其中Header声明 Token 类型和签名算法Payload保存用户相关信息例如用户 ID、用户名、过期时间Signature签名用于防止 Token 被篡改用户登录成功后服务端会生成 JWT 并返回给客户端。客户端后续请求接口时在请求头中携带这个 Token服务端验证通过后即可识别当前用户身份。三、准备环境本文示例环境Python 3.10 FastAPI Uvicorn python-jose passlib安装依赖python -m pip install fastapi uvicorn python-jose passlib[bcrypt] python-multipart说明fastapi Web 框架 uvicorn ASGI 服务 python-jose 生成和解析 JWT passlib[bcrypt] 密码加密与校验 python-multipart 支持表单登录项目结构fastapi-jwt-demo/ └── main.py四、完整代码创建main.py文件写入以下代码from datetime import datetime, timedelta from fastapi import FastAPI, Depends, HTTPException, status from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from jose import JWTError, jwt from passlib.context import CryptContext from pydantic import BaseModel app FastAPI() SECRET_KEY change-this-secret-key ALGORITHM HS256 ACCESS_TOKEN_EXPIRE_MINUTES 30 pwd_context CryptContext(schemes[bcrypt], deprecatedauto) oauth2_scheme OAuth2PasswordBearer(tokenUrl/login) fake_users_db { admin: { username: admin, hashed_password: pwd_context.hash(123456), disabled: False, } } class TokenResponse(BaseModel): access_token: str token_type: str class UserInfo(BaseModel): username: str disabled: bool False def verify_password(plain_password: str, hashed_password: str) - bool: return pwd_context.verify(plain_password, hashed_password) def authenticate_user(username: str, password: str): user fake_users_db.get(username) if not user: return None if not verify_password(password, user[hashed_password]): return None return UserInfo(usernameuser[username], disableduser[disabled]) def create_access_token(data: dict, expires_delta: timedelta): to_encode data.copy() expire datetime.utcnow() expires_delta to_encode.update({exp: expire}) encoded_jwt jwt.encode( to_encode, SECRET_KEY, algorithmALGORITHM, ) return encoded_jwt async def get_current_user(token: str Depends(oauth2_scheme)): credentials_exception HTTPException( status_codestatus.HTTP_401_UNAUTHORIZED, detailToken 无效或已过期, headers{WWW-Authenticate: Bearer}, ) try: payload jwt.decode( token, SECRET_KEY, algorithms[ALGORITHM], ) username payload.get(sub) if username is None: raise credentials_exception except JWTError: raise credentials_exception user fake_users_db.get(username) if user is None: raise credentials_exception return UserInfo(usernameuser[username], disableduser[disabled]) app.post(/login, response_modelTokenResponse) def login(form_data: OAuth2PasswordRequestForm Depends()): user authenticate_user( form_data.username, form_data.password, ) if not user: raise HTTPException( status_codestatus.HTTP_401_UNAUTHORIZED, detail用户名或密码错误, headers{WWW-Authenticate: Bearer}, ) access_token create_access_token( data{sub: user.username}, expires_deltatimedelta(minutesACCESS_TOKEN_EXPIRE_MINUTES), ) return { access_token: access_token, token_type: bearer, } app.get(/me, response_modelUserInfo) def read_current_user(current_user: UserInfo Depends(get_current_user)): return current_user app.get(/protected) def protected_api(current_user: UserInfo Depends(get_current_user)): return { message: 这是一个需要登录后才能访问的接口, user: current_user.username, }五、启动项目在main.py所在目录执行python -m uvicorn main:app --reload启动成功后浏览器访问http://127.0.0.1:8000/docs可以看到 FastAPI 自动生成的 Swagger 接口文档。六、测试账号本文示例内置了一个测试用户用户名admin 密码123456代码中使用hashed_password: pwd_context.hash(123456)运行时会自动生成密码哈希因此可以避免手动复制哈希字符串导致密码校验失败的问题。七、使用 Swagger 测试访问http://127.0.0.1:8000/docs点击右上角Authorize按钮。输入username: admin password: 123456认证成功后再访问GET /me GET /protected即可看到接口正常返回当前用户信息。八、使用命令行测试1. 登录获取 Token如果你使用的是 Windows PowerShell推荐使用curl.execurl.exe -X POST http://127.0.0.1:8000/login ^ -H Content-Type: application/x-www-form-urlencoded ^ -d usernameadminpassword123456如果你使用的是 macOS 或 Linuxcurl -X POST http://127.0.0.1:8000/login \ -H Content-Type: application/x-www-form-urlencoded \ -d usernameadminpassword123456返回结果示例{ access_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.xxxxx, token_type: bearer }2. 访问受保护接口将上一步返回的access_token放到请求头中。Windows PowerShellcurl.exe -X GET http://127.0.0.1:8000/protected ^ -H Authorization: Bearer 你的access_tokenmacOS 或 Linuxcurl -X GET http://127.0.0.1:8000/protected \ -H Authorization: Bearer 你的access_token成功返回示例{ message: 这是一个需要登录后才能访问的接口, user: admin }如果 Token 错误、缺失或过期则会返回 401。九、核心代码解析1. OAuth2PasswordBeareroauth2_scheme OAuth2PasswordBearer(tokenUrl/login)这行代码用于声明当前项目使用 Bearer Token 认证方式。当接口依赖oauth2_scheme时FastAPI 会自动从请求头中读取Authorization: Bearer token值2. 表单登录def login(form_data: OAuth2PasswordRequestForm Depends()):这里使用OAuth2PasswordRequestForm接收登录参数因此登录请求的格式是表单格式而不是 JSON 格式。请求参数为usernameadminpassword123456这种写法可以很好地配合 FastAPI 自带的 Swagger 授权功能。3. 密码校验def verify_password(plain_password: str, hashed_password: str) - bool: return pwd_context.verify(plain_password, hashed_password)项目中不要保存明文密码应保存加密后的密码哈希。本文为了方便演示直接在内存字典中模拟用户数据。4. 生成 JWTdef create_access_token(data: dict, expires_delta: timedelta): to_encode data.copy() expire datetime.utcnow() expires_delta to_encode.update({exp: expire}) encoded_jwt jwt.encode( to_encode, SECRET_KEY, algorithmALGORITHM, ) return encoded_jwt这里将用户身份信息和过期时间写入 JWT。其中sub通常用于保存用户唯一标识例如用户名或用户 ID。5. 校验 JWTpayload jwt.decode( token, SECRET_KEY, algorithms[ALGORITHM], )服务端使用相同的SECRET_KEY解析 Token。如果 Token 被篡改、签名不正确或已经过期解析时会抛出异常然后接口返回 401。6. 保护接口app.get(/protected) def protected_api(current_user: UserInfo Depends(get_current_user)):Depends(get_current_user)表示访问该接口前必须先完成 Token 校验。如果校验失败请求会直接返回 401不会继续执行接口主体。十、常见问题1. 为什么登录接口不是 JSON因为本文使用的是OAuth2PasswordRequestForm它接收的是表单格式数据方便和 FastAPI Swagger 的Authorize功能配合。如果想用 JSON 登录也可以自定义 Pydantic 模型但 Swagger 右上角的授权体验就没有这种方式直接。2. 为什么需要安装 python-multipart因为表单登录需要解析application/x-www-form-urlencoded或multipart/form-data类型的数据。如果没有安装python-multipart启动或请求时可能会出现表单解析相关错误。3. SECRET_KEY 可以随便写吗演示环境可以随便写但生产环境不建议硬编码在代码里。生产环境建议放到环境变量中例如JWT_SECRET_KEY一段足够复杂的随机字符串然后在代码中读取环境变量。4. Token 过期时间怎么设置本文设置为 30 分钟ACCESS_TOKEN_EXPIRE_MINUTES 30实际项目中需要根据业务场景决定。例如后台管理系统可以设置较短时间移动端应用可以结合 Refresh Token 延长登录状态高安全场景应设置更短有效期十一、实际项目优化方向本文示例为了便于理解使用内存字典模拟用户数据。真实项目中通常还需要做以下优化用户数据存储到数据库例如 MySQL、PostgreSQL、MongoDB。SECRET_KEY放到环境变量或配置中心。增加 Refresh Token 机制。增加用户注册接口。增加角色和权限控制。对 Token 加入黑名单机制用于支持主动退出登录。生产环境必须使用 HTTPS避免 Token 泄露。对登录接口增加限流防止暴力破解。统一封装认证异常和返回格式。按业务模块拆分目录结构避免所有代码写在一个文件中。十二、总结本文使用 FastAPI 实现了一个可直接运行的 JWT 登录认证示例完整覆盖了安装依赖、启动服务、登录获取 Token、携带 Token 访问受保护接口等流程。JWT 的优势是简单、无状态、适合前后端分离项目。掌握本文示例后可以继续扩展用户注册、权限控制、Refresh Token、后台管理系统登录等功能。对于 FastAPI 项目来说JWT 认证是非常常见的基础能力。建议在真实项目中结合数据库、环境变量、权限系统和统一异常处理进行进一步封装。