使用FastAPI-Login实现未登录用户重定向至登录页问题求助
问题原因
你当前代码没触发重定向,是因为fastapi_login的LoginManager在用户未认证时,会直接抛出InvalidCredentialsException或者带401状态码的HTTPException,而你的try-except块抓的是status.HTTP_401_UNAUTHORIZED(这只是个数值401),根本捕获不到实际抛出的异常,所以FastAPI会用默认逻辑返回JSON格式的401响应。
解决方案
给你两种可行的解决办法,按需选择:
方式一:全局异常处理器
通过FastAPI的异常处理器,捕获fastapi_login抛出的未认证异常,直接返回重定向。
修改后的代码:
from fastapi import ( Depends, FastAPI, HTTPException, status, Body, Request ) from fastapi.encoders import jsonable_encoder from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from fastapi.responses import HTMLResponse, RedirectResponse import app.models as models import app.database as database from datetime import datetime, timedelta from jose import JWTError, jwt from starlette.responses import FileResponse from fastapi_login import LoginManager from fastapi_login.exceptions import InvalidCredentialsException, NotAuthenticatedException from fastapi import Cookie import re app = FastAPI() # 替换成你实际的密钥 SECRET_KEY = "your-actual-secret-key" oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") manager = LoginManager(SECRET_KEY, token_url="/auth/login", use_cookie=True) manager.cookie_name = "token" # 处理未认证异常,自动重定向到登录页 @app.exception_handler(NotAuthenticatedException) async def auth_exception_handler(request: Request, exc: NotAuthenticatedException): return RedirectResponse(url="/login", status_code=status.HTTP_302_FOUND) # 登录页路由(需要你自己实现页面内容) @app.get("/login") async def show_login_page(): return FileResponse('login.html') @app.get("/") @app.get("/item") async def read_index(user=Depends(manager)): return FileResponse('item.html')
方式二:自定义认证依赖
自己写认证逻辑的依赖函数,在里面处理认证失败的情况,直接返回重定向。
修改后的代码:
from fastapi import ( Depends, FastAPI, HTTPException, status, Body, Request ) from fastapi.encoders import jsonable_encoder from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from fastapi.responses import HTMLResponse, RedirectResponse import app.models as models import app.database as database from datetime import datetime, timedelta from jose import JWTError, jwt from starlette.responses import FileResponse from fastapi_login import LoginManager from fastapi_login.exceptions import InvalidCredentialsException from fastapi import Cookie import re app = FastAPI() SECRET_KEY = "your-actual-secret-key" oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") manager = LoginManager(SECRET_KEY, token_url="/auth/login", use_cookie=True) manager.cookie_name = "token" # 自定义认证依赖,失败时重定向 async def get_authenticated_user(request: Request): try: user = await manager.get_current_user(request) return user except (InvalidCredentialsException, JWTError): # 通过HTTPException的headers返回重定向地址 raise HTTPException( status_code=status.HTTP_302_FOUND, headers={"Location": "/login"} ) @app.get("/login") async def show_login_page(): return FileResponse('login.html') @app.get("/") @app.get("/item") async def read_index(user=Depends(get_authenticated_user)): return FileResponse('item.html')
注意事项
- 方式一适合全局统一处理所有未认证请求的跳转,方式二更灵活,可针对特定路由调整逻辑。
- 必须确保
/login路由已经实现,能正确返回登录页面,否则重定向后会出现404错误。
内容的提问来源于stack exchange,提问作者Echchama Nayak
相关产品推荐
相关产品推荐

