news 2026/4/16 15:04:10

fastapi双token机制登录实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
fastapi双token机制登录实现

fastapi双token机制登录实现

一、整体架构

二、代码实现

from datetime import datetime, timedelta, timezone import uuid from redis import asyncio from fastapi import HTTPException, Depends,FastAPI,Response,Request from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials from jose import jwt, JWTError from pydantic import BaseModel from tortoise.contrib.fastapi import register_tortoise from app.config.model_conf.settings import TORTOISE_ORM from app.models.users import Users api_login = FastAPI() class user_login(BaseModel): username: str password: str class user_login_success(BaseModel): token: str token_type: str="Bearer" ACCESS_TOKEN_EXPIRE_MINUTES = 15 REFRESH_TOKEN_EXPIRE_DAYS = 7 SECRET_KEY = "CHANGE_ME_TO_32RANDOM_STRING" ALGORITHM = "HS256" REDIS_URL = "redis://192.168.88.14:6379/0" BLK_PREFIX = "black:jti:" REF_PREFIX = "refresh:" def create_access_token(username: str, jti: str) -> str: expire = datetime.now(timezone.utc) + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) return jwt.encode({"username": username, "jti": jti, "exp": expire}, SECRET_KEY, algorithm=ALGORITHM) # redis初始化 async def create_redis(): redis = await asyncio.from_url( REDIS_URL, decode_responses=True, max_connections=100, ) return redis @api_login.post("/login",response_model=user_login_success) async def login(user:user_login,response: Response,redis=Depends(create_redis)): user_info = Users.get(uername=user.username,password=user.password) if not user_info: raise HTTPException(status_code=401,detail="用户名或密码错误") # 生成access_token jti = str(uuid.uuid4()) access_token = create_access_token(user.username,jti) # 生成refresh_token,存储redis和cookie refresh_token = str(uuid.uuid4()) await redis.setex(REF_PREFIX+refresh_token,REFRESH_TOKEN_EXPIRE_DAYS*60*60*24,user.username) response.set_cookie( key="refresh_token", value=refresh_token, max_age=REFRESH_TOKEN_EXPIRE_DAYS*60*60*24, httponly=True, samesite="lax", secure=False, # 生产 True ) return {"token": access_token} # 解码token,验证token是否合法 def decode_token(token: str): try: return jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) except JWTError: return None # 获取当前登录用户信息 http_bearer = HTTPBearer(auto_error=True) async def get_current_user( cred: HTTPAuthorizationCredentials = Depends(http_bearer), redis=Depends(create_redis) ): # 解码token username_jti = decode_token(cred.credentials) print(username_jti) if not username_jti: raise HTTPException(status_code=401,detail="token无效") if not username_jti.get("username") or not username_jti.get("jti"): raise HTTPException(status_code=401,detail="token无效") # 验证用户是否已经退出 if await redis.exists(BLK_PREFIX+username_jti.get("jti")): raise HTTPException(status_code=401,detail="token已失效") return username_jti.get("username") # 重新签发access_token和refresh_token @api_login.post("/refresh") async def refresh(request: Request,response: Response,redis=Depends(create_redis),current_user: str = Depends(get_current_user)): # refresh_token存在,access_token失效,重新生成token # 判断并生成refresh_token refresh_token=request.cookies.get("refresh_token") if not refresh_token: raise HTTPException(status_code=401,detail="缺少 refresh_token") if not await redis.exists(REF_PREFIX+refresh_token): raise HTTPException(status_code=401,detail="refresh_token不存在") new_token = str(uuid.uuid4()) await redis.delete(REF_PREFIX+refresh_token) await redis.setex(REF_PREFIX+new_token,REFRESH_TOKEN_EXPIRE_DAYS*60*60*24,current_user) response.set_cookie( key="refresh_token", value=new_token, max_age=REFRESH_TOKEN_EXPIRE_DAYS*60*60*24, httponly=True, samesite="lax", secure=False, ) # 生成access_token new_jti = str(uuid.uuid4()) access_token = create_access_token(current_user,new_jti) return {"access_token":access_token} # 注销,依赖当前登录的用户,拉黑+删除token,redis @api_login.post("/logout") async def logout(request: Request,redis=Depends(create_redis), username_jti: str = Depends(get_current_user), cred: HTTPAuthorizationCredentials = Depends(http_bearer), ): # 退出,请求头获取token,拉黑当前请求的token header_token = decode_token(cred.credentials) await redis.setex(BLK_PREFIX+header_token.get("jti"),ACCESS_TOKEN_EXPIRE_MINUTES*60,1) # 从cookie中获取refresh_token,删除reids的refresh_token refresh_token = request.cookies.get("refresh_token") if refresh_token: await redis.delete(REF_PREFIX+refresh_token) else: raise HTTPException(status_code=401,detail="缺少refresh_token") return {"msg": "注销成功"} class user_register(BaseModel): msg: str @api_login.post("/register",response_model=user_register) async def register(user:user_login): # 1. 用户名重复检查 if await Users.filter(username=user.username).exists(): raise HTTPException(status_code=409, detail="用户已存在") if await Users.create(username=user.username, password=user.password): return {"msg": "注册成功,跳转到登录界面"} return {"msg": "注册失败"} # 数据库参数配置 register_tortoise( api_login, config=TORTOISE_ORM, ) if __name__ == "__main__": import uvicorn uvicorn.run(api_login, host="127.0.0.1", port=8000)
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/10 17:24:25

AI数字人对话系统终极指南:从零构建智能交互平台

AI数字人对话系统终极指南:从零构建智能交互平台 【免费下载链接】OpenAvatarChat 项目地址: https://gitcode.com/gh_mirrors/op/OpenAvatarChat 在人工智能技术飞速发展的今天,AI数字人对话系统正成为企业数字化转型和个人智能助手应用的重要工…

作者头像 李华
网站建设 2026/4/16 10:40:47

Wan2.2-T2V-A14B在法庭证据演示动画中的谨慎应用建议

Wan2.2-T2V-A14B在法庭证据演示动画中的谨慎应用建议 在一场复杂的刑事案件审理中,陪审团需要理解的可能不只是“谁做了什么”,而是动作发生的顺序、空间关系的逻辑、以及行为之间的因果链条。文字记录和口述证词虽然详尽,但对普通人来说&…

作者头像 李华
网站建设 2026/4/16 10:38:53

对比:传统ADB调试 vs AI辅助的问题解决效率

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 开发一个ADB效率对比测试工具,功能:1) 模拟ADB连接故障 2) 记录手动修复过程耗时 3) 自动修复流程耗时统计 4) 生成对比报告。使用Python实现,包…

作者头像 李华
网站建设 2026/4/16 10:44:11

基于多维度分析的海外网红营销精准选择与效果预测

在全球化营销快速演进的环境下,海外网红营销已从“凭感觉选人”走向“用数据决策”。尤其在品牌竞争加剧、内容形式不断演化的当下,如何精准筛选最适合品牌的海外网红,并在合作前对传播效果进行可预测性评估,已成为品牌能否提高投…

作者头像 李华
网站建设 2026/4/16 10:38:41

CoreProtect终极安装配置指南:快速搭建Minecraft服务器监控系统

快速上手篇:零基础安装指南 【免费下载链接】CoreProtect CoreProtect is a blazing fast data logging and anti-griefing tool for Minecraft servers. 项目地址: https://gitcode.com/gh_mirrors/co/CoreProtect 环境准备与前置检查 在开始安装CoreProte…

作者头像 李华
网站建设 2026/4/16 10:40:50

中文NLP语料库终极指南:五大核心数据集完整解析

你是否在为中文NLP项目寻找高质量语料而苦恼?面对海量数据却不知如何筛选?本文为你深度解析nlp_chinese_corpus项目中的五大核心数据集,带你轻松掌握千万级中文语料的应用之道。 【免费下载链接】nlp_chinese_corpus 大规模中文自然语言处理语…

作者头像 李华