news 2026/7/29 23:07:18

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/7/29 21:36:23

【国产】华为欧拉操作系统openEuler-LTS-22.03安装Docker-Compose保姆级教程

本文主要介绍华为欧拉操作系统 openEuler-LTS-22.03 安装Docker-Compose保姆级教程。后面文章将介绍通过 Docker Compose 一键部署应用。 一、Docker Compose介绍 Docker-Compose是Docker官方的开源项目,负责实现对Docker容器集群的快速编排。 Docker-Compose作用…

作者头像 李华
网站建设 2026/7/29 17:17:04

AI如何快速定位Nacos连接异常问题

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 创建一个工具,能够自动分析Nacos客户端连接异常(com.alibaba.nacos.api.exception.nacosexception: client not connected)的日志,并…

作者头像 李华
网站建设 2026/7/28 5:20:30

RxPermissions终极瘦身指南:5个技巧让AAR包体积减少40%

RxPermissions终极瘦身指南:5个技巧让AAR包体积减少40% 【免费下载链接】RxPermissions Android runtime permissions powered by RxJava2 项目地址: https://gitcode.com/gh_mirrors/rx/RxPermissions 在Android应用开发中,第三方库的体积优化一…

作者头像 李华
网站建设 2026/7/29 11:14:57

全方位解析MMRotate:旋转目标检测的终极解决方案

全方位解析MMRotate:旋转目标检测的终极解决方案 【免费下载链接】mmrotate OpenMMLab Rotated Object Detection Toolbox and Benchmark 项目地址: https://gitcode.com/gh_mirrors/mm/mmrotate 在当今计算机视觉领域,旋转目标检测技术正以前所未…

作者头像 李华
网站建设 2026/7/28 9:47:51

MATLAB编程:Sagnac环串并联结构微波光子滤波器滤波响应及频率响应分析

MATLAB编程:基于串并联Sagnac环的微波光子滤波器滤波响应频率响应分析。本文针对“基于串并联Sagnac环的微波光子滤波器滤波响应频率响应分析”相关MATLAB代码展开功能解析,代码包含SagnacH.m函数文件与SagnacSTST_H.m主程序文件,二者协同实现…

作者头像 李华