Auth0 Flask Web 应用集成
使用 auth0-server-python 将登录、注销和用户资料添加到 Flask Web 应用中。
前提条件
Flask 应用
Auth0 正常 Web 应用配置(不是 API —— 必须是应用)
如果您尚未设置 Auth0,请先使用 auth0-quickstart 技能
何时不使用
Python API 与 JWT Bearer 验证 —— 使用 auth0-fastapi-api для FastAPI,或查看 Django REST Framework 快速入门
FastAPI Web 应用带有登录/注销 UI —— 尚无专用技能;请查看 FastAPI 快速入门
单页应用 —— 使用 auth0-react、auth0-vue 或 auth0-angular 进行客户端身份验证
Next.js 应用 —— 使用 auth0-nextjs,它同时处理客户端和服务器
Node.js Web 应用 —— 使用 auth0-express 或 auth0-fastify 进行基于会话的身份验证
快速入门工作流
pip install auth0-server-python "flask[async]" python-dotenv
重要:您必须安装 flask[async](而不是仅仅 flask)。[async] 额外安装 asgiref,这是 Flask 2.0+ 支持异步 def 路由处理程序所必需的。没有它,异步路由将不起作用。在 requirements.txt 中,使用 flask[async]>=2.0.0。
创建 .env:
AUTH0_DOMAIN=your-tenant.us.auth0.com
AUTH0_CLIENT_ID=your_client_id
AUTH0_CLIENT_SECRET=your_client_secret
AUTH0_SECRET=your_generated_app_secret
AUTH0_REDIRECT_URI=http://localhost:5000/callback
AUTH0_DOMAIN 是您的 Auth0 租户域(不包括 https://)。
AUTH0_CLIENT_ID 和 AUTH0_CLIENT_SECRET 来自您的 Auth0 应用设置。
AUTH0_SECRET 用于加密会话数据 —— 使用 openssl rand -hex 64 生成。
在您的 Auth0 应用设置中:
允许的回调 URL:http://localhost:5000/callback
允许的注销 URL:http://localhost:5000
创建 auth.py 以初始化带有 Flask 会话的 ServerClient。存储使用 Flask 的内置会话(默认为基于 cookie 的)进行无状态设置 —— 无需外部数据库:
导入 os
从 flask 导入 session 作为 flask_session
从 auth0_server_python.auth_server.server_client 导入 ServerClient
从 auth0_server_python.auth_types 导入 StateData、TransactionData
从 auth0_server_python.store 导入 StateStore、TransactionStore
从 dotenv 导入 load_dotenv
load_dotenv() # 默认使用 .env;传递 load_dotenv(".env.local") 如果凭据在 .env.local 中
类 FlaskSessionStateStore(StateStore):
"""使用 Flask 会话进行持久化的状态存储。"""
def __init__(self, secret: str):
super().__init__({"secret": secret})
异步 def set(self, identifier, state, remove_if_expires=False, options=None):
data = state.dict() if hasattr(state, "dict") else state
flask_session[identifier] = self.encrypt(identifier, data)
异步 def get(self, identifier, options=None):
data = flask_session.get(identifier)
if data is None:
return None
decrypted = self.decrypt(identifier, data)
# 确保不返回 dict,因为底层 SDK 期望 StateData 实例,而不是 dict
return StateData(
decrypted) if isinstance(decrypted, dict) else decrypted
异步 def delete(self, identifier, options=None):
flask_session.pop(identifier, None)
异步 def delete_by_logout_token(self, claims, options=None):
pass
类 FlaskSessionTransactionStore(TransactionStore):
"""使用 Flask 会话进行持久化的事务存储。"""
def __init__(self, secret: str):
super().__init__({"secret": secret})
异步 def set(self, identifier, state, remove_if_expires=False, options=None):
data = state.dict() if hasattr(state, "dict") else state
flask_session[identifier] = self.encrypt(identifier, data)
异步 def get(self, identifier, options=None):
data = flask_session.get(identifier)
if data is None:
return None
decrypted = self.decrypt(identifier, data)
# 确保不返回 dict,因为底层 SDK 期望 TransactionData 实例,而不是 dict
return TransactionData(decrypted) if isinstance(decrypted, dict) else decrypted
异步 def delete(self, identifier, options=None):
flask_session.pop(identifier, None)
secret = os.getenv("AUTH0_SECRET")
auth0 = ServerClient(
域 = os.getenv("AUTH0_DOMAIN"),
client_id = os.getenv("AUTH0_CLIENT_ID"),
client_secret = os.getenv("AUTH0_CLIENT_SECRET"),
secret = secret,
redirect_uri = os.getenv("AUTH0_REDIRECT_URI"),
state_store = FlaskSessionStateStore(secret=secret),
transaction_store = FlaskSessionTransactionStore(secret=secret),
authorization_params = {"scope": "openid profile email"},
)
创建一个 ServerClient 实例并重用它。永远不要硬编码凭据 —— 始终使用环境变量。
工作原理:
Flask 的默认会话是基于 cookie 的(无状态)。
SDK 使用 JWE 在将会话数据(令牌、用户资料)存储在会话之前对其进行加密。