FastAPI结合Authlib外部OAuth认证:正确复用客户端的疑问
改进Authlib与FastAPI的协作实现
核心优化点
- 移除手动存储/读取
access_token的冗余代码 - 利用Authlib内置的令牌管理机制实现自动刷新
- 通过官方推荐的客户端调用方式简化外部API请求
修改后的完整代码
from authlib.integrations.base_client import OAuthError from authlib.integrations.starlette_client import OAuth from fastapi import FastAPI, HTTPException from starlette.requests import Request from starlette.responses import HTMLResponse, RedirectResponse from starlette.middleware.sessions import SessionMiddleware app = FastAPI() app.add_middleware(SessionMiddleware, secret_key="some-random-string") oauth = OAuth() oauth.register( name="oauthprovider", client_id="MYCLIENTID", client_secret="MYCLIENTSECRET", server_metadata_url="https://example.com/.well-known/openid-configuration", # 显式开启自动刷新(默认已启用,声明后更清晰) auto_refresh_url=None, refresh_token_url=None, ) @app.get('/login') async def login(request: Request): redirect_uri = "http://localhost:8000/auth/callback" return await oauth.oauthprovider.authorize_redirect(request, redirect_uri) @app.get('/auth/callback') async def auth(request: Request): try: # Authlib会自动将完整令牌对象存入session,无需手动处理 token = await oauth.oauthprovider.authorize_access_token(request) except OAuthError as error: return HTMLResponse(f'<h1>{error.error}</h1>') user = token.get('userinfo') if user: request.session['user'] = dict(user) # 移除手动存储access_token的代码 return RedirectResponse(url='/docs') @app.get('/fetchexternalAPI') async def externalAPI(request: Request): try: # 使用Authlib客户端的异步方法,自动处理令牌获取与刷新 response = await oauth.oauthprovider.get( "https://example.com/api", request=request ) response.raise_for_status() return response.json() except Exception as e: raise HTTPException(status_code=500, detail=str(e))
关键细节说明
- 令牌自动存储:
authorize_access_token方法会把包含access_token、refresh_token、过期时间的完整令牌对象,自动序列化存入session的_oauth_oauthprovider_token键下(命名规则为_oauth_<provider_name>_token)。 - 自动刷新逻辑:调用客户端的
get/post等方法时,Authlib会自动检查令牌是否过期。如果过期且存在有效refresh_token,会自动向授权服务器请求刷新令牌,并更新session中的令牌数据,全程无需手动干预。 - 异步架构适配:使用Authlib提供的异步HTTP方法,与FastAPI的异步模型匹配,避免阻塞事件循环。
额外注意事项
- 确保授权服务器返回的令牌包含
refresh_token和expires_in字段,否则自动刷新无法生效。 - 生产环境中,SessionMiddleware的
secret_key必须使用安全的随机字符串,禁止硬编码。
内容的提问来源于stack exchange,提问作者tenup
相关产品推荐
相关产品推荐

