在Flask应用中使用基于会话的身份验证实现登录、登出和用户资料,集成auth0-server-python进行服务端渲染
Auth0 Flask 网络应用集成.是一项面向实际任务的技能,主要用于Add 登录,登录,以及用户配置到一个使用 aut0-server-python.;Prerequisites.;
使用时应结合输入条件选择合适的执行方式,核对必要参数、依赖环境与输出内容,并按原始要求处理异常情况。从功能定位来看,该技能强调把分散的操作要求整理成清晰、可复用的处理流程,使用户能够围绕既定目标快速准备输入、选择执行方式并获得结构化结果。实际使用前应先确认任务范围、数据来源、运行环境、必要权限和关键参数,再依据技能说明逐步执行;若输入条件不完整,应先补齐信息或采用保守配置,避免因错误假设导致结果偏离需求。
执行过程中需要关注工具调用是否成功、接口或依赖是否可用、输出格式是否符合预期,并对异常提示、缺失字段和边界情况进行处理;涉及批量任务时,还应保存进度,避免中断后重复操作。该技能适合用于一次性任务,也可以接入自动化工作流,与其他技能或上层代理配合完成更完整的业务链路;在组合使用时,应明确每一步的输入输出关系,并避免不同步骤之间出现参数冲突。
使用 auth0-server-python 为 Flask Web 应用添加登录、登出和用户资料功能。
auth0-quickstart 技能auth0-fastapi-api,或参考 Django REST Framework 快速入门指南auth0-react、auth0-vue 或 auth0-angularauth0-nextjs,它同时支持客户端与服务端逻辑auth0-express 或 auth0-fastify 实现基于会话的身份验证pip install auth0-server-python "flask[async]" python-dotenv
关键注意:必须安装 flask[async](而非仅 flask)。[async] 扩展将安装 asgiref,这是 Flask 2.0+ 支持 async 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 应用设置中:
http://localhost:5000/callbackhttp://localhost:5000创建 auth.py,使用 Flask 的会话机制初始化 ServerClient。这些存储器默认使用 Flask 内置的 session(基于 Cookie)实现无状态(stateless)部署,无需外部数据库:
import os
from flask import session as flask_session
from auth0_server_python.auth_server.server_client import ServerClient
from auth0_server_python.auth_types import StateData, TransactionData
from auth0_server_python.store import StateStore, TransactionStore
from dotenv import load_dotenv
load_dotenv() # 默认读取 .env;如凭据存于 .env.local,请传入 load_dotenv(".env.local")
class FlaskSessionStateStore(StateStore):
"""使用 Flask session 持久化状态的存储器。"""
def __init__(self, secret: str):
super().__init__({"secret": secret})
async 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)
async 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 实例而非字典
return StateData(**decrypted) if isinstance(decrypted, dict) else decrypted
async def delete(self, identifier, options=None):
flask_session.pop(identifier, None)
async def delete_by_logout_token(self, claims, options=None):
pass
class FlaskSessionTransactionStore(TransactionStore):
"""使用 Flask session 持久化事务的存储器。"""
def __init__(self, secret: str):
super().__init__({"secret": secret})
async 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)
async 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 实例而非字典
return TransactionData(**decrypted) if isinstance(decrypted, dict) else decrypted
async def delete(self, identifier, options=None):
flask_session.pop(identifier, None)
secret = os.getenv("AUTH0_SECRET")
auth0 = ServerClient(
domain=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 进行加密,确保 Cookie 中的数据既被签名又加密。无需服务端数据库。
无需 store_options 或 before_request: SDK 支持向存储方法传递 store_options(例如 request/response 对象)。由于本示例中的存储器使用 flask.session(在请求生命周期内全局可用),因此不需要从 store_options 获取任何参数,可直接调用 SDK 方法而无需传入该参数。若你实现了一个直接管理 Cookie 的自定义存储器(而非使用 flask.session),则需重新引入 store_options 并传入 {"request": request, "response": response}。
关于 Cookie 大小: 无状态会话将全部数据存于 Cookie(约 4KB 上限),对大多数应用已足够。若存储大量会话数据或接近 Cookie 大小限制,请切换至有状态(stateful)部署方案。
在 app.py 中,配置 Flask 的密钥及会话选项:
import os
from flask import Flask, redirect, request
from auth import auth0
from dotenv import load_dotenv
load_dotenv()
app = Flask(__name__)
app.secret_key = os.getenv("AUTH0_SECRET")
app.config.update(
SESSION_COOKIE_SECURE=False, # 生产环境需设为 True(要求 HTTPS)
SESSION_COOKIE_HTTPONLY=True,
SESSION_COOKIE_SAMESITE="Lax",
)
关键注意: 必须设置 app.secret_key,否则 Flask 会话机制无法工作。
生产环境注意事项: 部署于 HTTPS 环境时,必须将 SESSION_COOKIE_SECURE 设为 True。若在生产环境中保持 False,会话 Cookie 将通过未加密连接传输。
@app.route("/")
async def home():
user = await auth0.get_user()
if user:
return f"Hello, {user['name']}! Profile | Logout"
return "Welcome! Login"
@app.route("/login")
async def login():
authorization_url = await auth0.start_interactive_login()
return redirect(authorization_url)
start_interactive_login() 返回指向 Auth0 通用登录页(Universal Login Page)的 URL 字符串,你必须将其包裹在 redirect() 中。授权参数(如 scope、redirect_uri)已在 ServerClient 初始化时配置完成。
@app.route("/callback")
async def callback():
try:
await auth0.complete_interactive_login(str(request.url))
return redirect("/")
except Exception as e:
return f"Authentication error: {str(e)}", 400
第一个参数必须传入 str(request.url) —— 即包含授权码查询参数的完整回调 URL。务必用 try/except 包裹,因为令牌交换可能失败(例如授权码过期、CSRF 校验失败)。
@app.route("/profile")
async def profile():
user = await auth0.get_user()
if user is None:
return redirect("/login")
return (
f"{user['name']}
"
f"Email: {user['email']}
"
f"
"
f""
)
get_user() 从会话中返回当前用户资料,若未登录则返回 None。
@app.route("/logout")
async def logout():
url = await auth0.logout()
return redirect(url)
logout() 返回 Auth0 的登出 URL,需重定向用户至此地址。
flask run
访问 http://localhost:5000/login 启动登录流程。
对于生产环境应用,或当会话数据超出 Cookie 大小限制时,可使用 Flask-Session 配合 Redis 将会话数据存储在服务端。此时 Cookie 中仅保存会话 ID。
pip install flask-session redis
更新 app.py 以启用 Redis 后端会话:
import os
from flask import Flask, redirect, request
from flask_session import Session
from auth import auth0
from dotenv import load_dotenv
load_dotenv()
app = Flask(__name__)
app.secret_key = os.getenv("AUTH0_SECRET")
app.config.update(
SESSION_TYPE="redis",
SESSION_PERMANENT=True,
SESSION_KEY_PREFIX="auth0:",
SESSION_COOKIE_SECURE=False,
SESSION_COOKIE_HTTPONLY=True,
SESSION_COOKIE_SAMESITE="Lax",
)
Session(app)
auth.py 中的 FlaskSessionStateStore 和 FlaskSessionTransactionStore 可直接复用,无需任何更改。Flask-Session 会透明地将 flask.session 的后端从 Cookie 切换为 Redis,而存储器仍像之前一样继续使用 flask.session 接口。
路由代码完全一致 —— 与无状态部署相比,无需任何代码变更。
| 错误 | 修正方式 |
|---|---|
在源码中硬编码 domain、client_id 或 client_secret |
始终从环境变量读取 —— 切勿将凭据嵌入代码 |
直接使用 Authlib 或 python-jose |
无需手动处理;auth0-server-python 已完整封装所有 OAuth/OIDC 流程 |
使用 Flask-Login 或 Flask-Dance |
无需额外集成;SDK 自身管理会话与身份验证 |
手动调用 jwt.decode() 解析 JWT |
SDK 内部已处理令牌校验,无需自行解析 |
安装 flask 时未指定 [async] 扩展 |
必须在 requirements.txt 中声明 flask[async]>=2.0.0;否则异步路由处理器将静默失效 |
使用同步路由处理器(def) |
所有调用 SDK 方法的路由必须声明为 async def 并使用 await |
遗漏 app.secret_key |
Flask 会话管理所必需 —— 缺失将导致会话静默失败 |
在 Flask 应用中误用 auth0-fastapi-api |
该包专为 FastAPI API 设计;Flask 应使用 auth0-server-python |
将 domain 参数传为含 https:// 的完整 URL |
domain 应仅为裸域名,例如 my-tenant.us.auth0.com,而非 https://my-tenant.us.auth0.com |
| 未在 Auth0 控制台配置回调 URL | 必须将 http://localhost:5000/callback 添加至“允许的回调 URL”列表 |
直接返回 start_interactive_login() 结果 |
该方法返回字符串形式的 URL,并非响应对象 —— 必须包裹在 redirect() 中 |
未在 /callback 路由中处理异常 |
complete_interactive_login() 可能失败 —— 务必使用 try/except 包裹 |
调用 SDK 方法时遗漏 await |
所有 SDK 方法均为异步 —— 遗漏 await 将返回协程对象而非实际结果 |
以位置参数方式向 logout() 传入 store_options |
应使用关键字参数 logout(store_options=...) —— 第一个位置参数是 LogoutOptions,而非 store_options |
| 期望后通道登出(backchannel logout)生效 | Cookie-based sessions 不支持此功能 —— delete_by_logout_token 是空操作(no-op)。请使用标准 /logout 路由 |
以 SESSION_COOKIE_SECURE=False 部署至生产环境 |
生产环境必须设为 True —— 否则 Cookie 将通过 HTTP 明文传输 |
所有方法均为异步:
| 方法 | 签名 | 用途 |
|---|---|---|
start_interactive_login |
await auth0.start_interactive_login() |
返回授权 URL 字符串 —— 需包裹在 redirect() 中 |
complete_interactive_login |
await auth0.complete_interactive_login(str(request.url)) |
处理回调 URL,交换授权码获取令牌 |
get_user |
await auth0.get_user() |
返回当前会话用户字典,未登录时返回 None |
get_access_token |
await auth0.get_access_token() |
返回用于调用外部 API 的访问令牌(access token) |
logout |
await auth0.logout() |
返回 Auth0 登出 URL 字符串 |
auth0-express — 适用于带登录/登出会话的服务器渲染 Express Web 应用auth0-fastify — 适用于基于会话鉴权的 Fastify Web 应用auth0-cli — 从终端管理 Auth0 资源ServerClient 配置:
auth0 = ServerClient(
domain=os.getenv("AUTH0_DOMAIN"), # 必需
client_id=os.getenv("AUTH0_CLIENT_ID"), # 必需
client_secret=os.getenv("AUTH0_CLIENT_SECRET"), # 必需
secret=os.getenv("AUTH0_SECRET"), # 必需(加密密钥)
redirect_uri=os.getenv("AUTH0_REDIRECT_URI"), # 必需
state_store=FlaskSessionStateStore(secret=secret), # 必需
transaction_store=FlaskSessionTransactionStore(secret=secret), # 必需
authorization_params={"scope": "openid profile email"}, # 推荐
)
路由保护模式:
user = await auth0.get_user()
if user is None:
return redirect("/login")
环境变量:
AUTH0_DOMAIN — 你的 Auth0 租户域名(例如 tenant.us.auth0.com)AUTH0_CLIENT_ID — 你的应用的 Client IDAUTH0_CLIENT_SECRET — 你的应用的 Client SecretAUTH0_SECRET — 加密及会话密钥AUTH0_REDIRECT_URI — 回调 URL(例如 http://localhost:5000/callback)auth0-server-python PyPI 页面相关专题
热门下载
相关下载
精品课程
共0课时 | 0人学习
共0课时 | 0人学习
共0课时 | 0人学习