news 2026/5/26 8:31:55

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/5/25 16:03:28

构建高效计算机专业课记忆系统:模块化方法论指南

构建高效计算机专业课记忆系统:模块化方法论指南 【免费下载链接】CS-Xmind-Note 计算机专业课(408)思维导图和笔记:计算机组成原理(第五版 王爱英),数据结构(王道)&…

作者头像 李华
网站建设 2026/5/26 5:10:13

探索 A*与 DWA 融合:小白也能懂的路径规划算法之旅

AStar搜索算法,A*和DWA算法融合,适合小白学习哦 程序效果如图所示最近在研究路径规划算法,发现 A*和 DWA 算法都各有千秋,要是把它们融合起来,那效果简直绝了。今天就来跟各位小白分享下这俩算法以及它们融合后的神奇之…

作者头像 李华
网站建设 2026/5/25 7:48:58

计算机毕设java校园志愿服务管理系统 基于Java的校园志愿活动信息化管理系统设计与实现 Java技术驱动的校园志愿服务管理平台开发

计算机毕设java校园志愿服务管理系统a9y349(配套有源码 程序 mysql数据库 论文) 本套源码可以在文本联xi,先看具体系统功能演示视频领取,可分享源码参考。随着互联网技术的飞速发展,校园志愿服务管理的方式也在不断革新。传统的纸…

作者头像 李华
网站建设 2026/5/26 6:13:20

企业级可观测平台哪家好:全球6家智能可观测厂商实力排名

Gartner预测,到2027年,超过50%的企业将使用可观测性技术来优化业务决策,这一比例远高于2022年的不足20%。现代分布式架构、微服务、容器化和多云环境使得传统的监控手段已无法满足企业对系统状态全面洞察的需求。 面对市场上众多的可观测解决…

作者头像 李华
网站建设 2026/5/25 12:46:46

Android RecyclerView视频自动播放终极指南:5分钟快速集成

Android RecyclerView视频自动播放终极指南:5分钟快速集成 【免费下载链接】AutoplayVideos Android library to auto-play/pause videos from url in recyclerview. 项目地址: https://gitcode.com/gh_mirrors/au/AutoplayVideos 想要在Android应用中实现类…

作者头像 李华
网站建设 2026/5/26 6:12:16

Zen Browser:重新定义高效浏览的桌面伴侣

Zen Browser:重新定义高效浏览的桌面伴侣 【免费下载链接】desktop 🌀 Experience tranquillity while browsing the web without people tracking you! 项目地址: https://gitcode.com/GitHub_Trending/desktop70/desktop 在信息爆炸的时代&…

作者头像 李华