主题
你可以使用 GitHub、Google、Azure、Auth0、LinkedIn 等第三方身份提供商,在你的 Flet 应用中实现用户身份验证(即「使用 X 登录」按钮)。
身份提供商必须支持 OAuth 2.0 授权码流,才能获取 API 访问令牌。
内置的 Flet 凭据登录与用户管理功能计划在未来版本中推出。如果你需要在应用中创建并管理用户账户,可以自行实现,也可以使用提供丰厚免费层级的 Auth0 身份提供商。
Flet 身份验证特性:
- 兼容 Flet 桌面、网页以及移动端应用。
- 允许在单个应用中同时使用多个身份验证提供商。
- 内置对以下 OAuth 提供商的支持,并能自动拉取用户详细信息:
- GitHub
- Azure
- Auth0
- 支持获取用户所在组(groups)。
- 支持令牌(Token)自动刷新。
- 支持使用已保存的令牌登录(即「记住我」功能)。
- 支持自定义任何兼容 OAuth 的身份验证提供商。
登录流程概述
- 配置好 OAuth 提供商(内置或通用),指定 Client ID、Client secret 以及重定向 URL(Redirect URL)。
- 调用
await page.login(provider)启动 OAuth 网页授权流。 - 用户被重定向到 OAuth 提供商的官方网站。
- 用户在提供商网站上登录,并授权同意应用以所请求的 scope 访问业务 API。
- 提供商网站携带着授权码重定向回 Flet 的 OAuth 回调 URL。
- Flet 用授权码换取令牌,并调用
page.on_login事件处理器。 - Flet 应用可以通过
await page.auth.get_token()获取 API 令牌,并从page.auth.user读取用户详细信息。
配置 OAuth 提供商
Flet 内置支持以下 OAuth 提供商:GitHub、Azure、Google、Auth0。此外,你也可以配置一个通用 OAuth 提供商,并自行提供授权(authorization)、令牌(token)以及用户信息(user info)端点。
本指南中,我们将演示如何配置以 GitHub 账号登录 Flet。
要将 Flet 身份验证与 GitHub 集成,需先注册一个新的 GitHub OAuth 应用(Profile settings → Developer settings → OAuth Apps)。
Authorization callback URL 应采用如下格式:
{application-url}/oauth_callback
在 OAuth 应用详情页面点击 "Generate a new client secret" 按钮。将 "Client ID" 和 "Client secret" 复制到安全的地方 —— 你会在 Flet 应用中用到它们。

使用 OAuth 提供商登录
身份验证调用都是异步的。请在 async def 事件处理器或异步的 main() 中使用它们;下面较短的代码片段都假定处于该异步上下文中。
python
import os
import flet as ft
from flet.auth.providers import GitHubOAuthProvider
GITHUB_CLIENT_ID = os.getenv("GITHUB_CLIENT_ID")
assert GITHUB_CLIENT_ID, "set GITHUB_CLIENT_ID environment variable"
GITHUB_CLIENT_SECRET = os.getenv("GITHUB_CLIENT_SECRET")
assert GITHUB_CLIENT_SECRET, "set GITHUB_CLIENT_SECRET environment variable"
def main(page: ft.Page):
provider = GitHubOAuthProvider(
client_id=GITHUB_CLIENT_ID,
client_secret=GITHUB_CLIENT_SECRET,
redirect_url="http://localhost:8550/oauth_callback",
)
async def login_click(e):
await page.login(provider)
async def on_login(e):
if e.error:
print("Login error:", e.error)
return
token = await page.auth.get_token()
print("Access token:", token.access_token)
print("User ID:", page.auth.user.id)
page.on_login = on_login
page.add(ft.Button("Login with GitHub", on_click=login_click))
ft.run(main, port=8550, view=ft.AppView.WEB_BROWSER)注意
请注意,我们从环境变量中读取 OAuth 应用的 Client ID 和 Client secret。切勿将任何密钥硬编码进源码,以免不慎暴露给公众!
在运行应用之前,在命令行中设置好这两个密钥环境变量:
$ export GITHUB_CLIENT_ID="<client_id>"
$ export GITHUB_CLIENT_SECRET="<client_secret>"运行程序并点击 "Login with GitHub" 按钮,GitHub 的授权页面将在以下位置打开:
- 桌面端应用 —— 一个新的浏览器窗口或标签页。
- 网页端应用 —— 一个新的弹窗窗口(请确保弹窗拦截已关闭)。
- 移动端应用 —— 应用内 Web 浏览器。

重定向 URL
我们在注册 GitHub OAuth 应用时使用了 http://localhost:8550/oauth_callback 作为重定向 URL。注意它包含固定的端口 8550。要在固定端口上运行 Flet 应用,请在 ft.run() 调用中传入 port 参数:
python
ft.run(main, port=8550)授权范围
大多数 OAuth 提供商允许应用请求一个或多个 scope,以限制应用对用户账户的访问权限。
Flet 内置的提供商默认会请求访问用户资料的 scope,但你也可以在登录方法中请求额外的 scope,例如上面示例中的 public_repo:
python
await page.login(
provider,
scope=["public_repo"]
)page.login() 方法带有多个用于控制身份验证流程的参数:
fetch_user(bool) —— 是否将用户详细信息拉取到page.auth.user。默认为True。fetch_groups(bool) —— 是否将用户组拉取到page.auth.user.groups。默认为False。scope—— 要请求的 scope 列表。saved_token—— 用于恢复授权的 OAuth 令牌 JSON 快照。用await page.auth.get_token()获取令牌,以token.to_json()序列化,然后加密并保存到客户端存储。见下文。on_open_authorization_url—— 用于打开授权 URL 所在浏览器的回调。见下文。complete_page_html—— 「你已成功通过身份验证,现在可以关闭此页面」页面的自定义 HTML 内容。redirect_to_page(bool) —— 仅用于 Flet web 应用,当授权页在同一浏览器标签页中打开时使用。
await page.login() 返回一个授权对象。默认实现提供:
get_token()—— 一个异步方法,返回 OAuth 令牌,并在需要时自动刷新。见下文。user—— 用户详细信息,含一个必填的id字段,以及 OAuth 提供商特定的其他字段。provider—— 用于此次授权的 OAuth 提供商实例。
最后一次授权的引用保存在 page.auth 属性中。
如果你的应用允许使用多个 OAuth 提供商授权,你可以把授权保存在会话(session)中,例如:
python
page.session["github_auth"] = await page.login(github_provider)
page.session["google_auth"] = await page.login(google_provider)检查身份验证结果
无论授权成功还是失败,都会调用 page.on_login 事件处理器。
事件处理器参数 e 是 LoginEvent 类的实例,具有以下属性:
error(str) —— OAuth 错误。error_description(str) —— OAuth 错误描述。
当 error 为空字符串时,说明授权成功。
你可以用这个事件处理器来切换登录/注销的界面,例如:
python
import os
import flet as ft
from flet.auth.providers import GitHubOAuthProvider
def main(page: ft.Page):
provider = GitHubOAuthProvider(
client_id=os.getenv("GITHUB_CLIENT_ID"),
client_secret=os.getenv("GITHUB_CLIENT_SECRET"),
redirect_url="http://localhost:8550/oauth_callback",
)
async def login_button_click(e):
await page.login(provider, scope=["public_repo"])
def on_login(e: ft.LoginEvent):
if not e.error:
toggle_login_buttons()
def logout_button_click(e):
page.logout()
def on_logout(e):
toggle_login_buttons()
def toggle_login_buttons():
login_button.visible = page.auth is None
logout_button.visible = page.auth is not None
page.update()
login_button = ft.Button("Login with GitHub", on_click=login_button_click)
logout_button = ft.Button("Logout", on_click=logout_button_click)
toggle_login_buttons()
page.on_login = on_login
page.on_logout = on_logout
page.add(login_button, logout_button)
ft.run(main, port=8550, view=ft.AppView.WEB_BROWSER)访问用户详细信息
如果调用 page.login() 时传入 fetch_user=True(默认),用户资料会被赋值给 page.auth.user。
所有内置的 OAuth 提供商都实现了 user.id 属性 —— 一个唯一的用户标识符,其值取决于具体提供商(数字、Guid 或 Email),可在你的应用中作为用户的 key 使用。
其余的用户资料属性取决于提供商,可用索引器访问。例如,要打印 GitHub 用户的某些属性:
python
print("Name:", page.auth.user["name"])
print("Login:", page.auth.user["login"])
print("Email:", page.auth.user["email"])使用 OAuth 令牌
授权成功后,用 token = await page.auth.get_token() 获取 OAuth 令牌。该令牌具有以下属性:
access_token—— 访问令牌,用作 API 请求头中的授权令牌。scope—— 令牌的 scope。token_type—— 访问令牌类型,如Bearer。expires_in—— 可选的、距令牌过期的秒数。expires_at—— 可选的、令牌过期的时刻(time.time()+expires_in)。refresh_token—— 可选的刷新令牌,用于获取新的访问令牌。
使用 token.access_token 来调用提供商的 API。例如,下面这个异步处理器列出了用户的 GitHub 仓库,且不会阻塞应用的事件循环:
python
import asyncio
import requests
async def list_repositories(e):
token = await page.auth.get_token()
headers = {"Authorization": f"Bearer {token.access_token}"}
response = await asyncio.to_thread(
requests.get, "https://api.github.com/user/repos", headers=headers, timeout=30
)
response.raise_for_status()
for repo in response.json():
print(repo["full_name"])INFO
在每次 API 操作前都调用 await page.auth.get_token(),以便 Flet 能刷新已过期的令牌。保留较早操作的令牌、之后再复用其 access_token 会绕过该刷新检查。
保存和恢复授权令牌
要实现持久登录(登录页上的「记住我」复选框),你可以把授权令牌保存到客户端存储,并在用户下次打开 Flet 应用时用它登录。
将授权令牌序列化为 JSON:
python
token = await page.auth.get_token()
jt = token.to_json()警告
在向客户端存储发送数据前,请对敏感数据进行加密。
Flet 内置了使用对称算法(加密和解密使用同一个密钥)加密文本数据的工具方法。它们采用 cryptography 包中的 Fernet 实现(AES 128 加一些额外加固),并用 PBKDF2 从用户密码句中导出加密密钥。
加密 JSON 令牌:
python
import os
from flet.security import encrypt, decrypt
secret_key = os.getenv("MY_APP_SECRET_KEY")
# 返回 base64 编码的字符串
ejt = encrypt(jt, secret_key)警告
请注意,我们从环境变量中读取对称加密所用的密钥(或称密码句、密码等)。切勿将任何密钥硬编码进源码,以免不慎暴露给公众!
在运行应用之前,在命令行中设置好该密钥:
$ export MY_APP_SECRET_KEY="<secret>"现在,加密后的值可以存入客户端存储:
python
prefs = ft.SharedPreferences()
await prefs.set("myapp.auth_token", ejt)下次用户打开应用时,你可以从客户端存储读取加密令牌,若存在则解密并用于 page.login():
python
ejt = await prefs.get("myapp.auth_token")
if ejt:
jt = decrypt(ejt, secret_key)
await page.login(provider, saved_token=jt)注销登录
调用 page.logout() 会重置 page.auth 引用,并触发 page.on_logout 事件处理器。
你可以在注销方法中移除已保存的令牌,例如:
python
async def logout_button_click(e):
await prefs.remove(AUTH_TOKEN_KEY)
page.logout()自定义授权流程
默认情况下,OAuth 授权流发生在新的浏览器窗口/标签页(桌面端应用)、浏览器弹窗(网页端)或应用内 Web 视图(移动端)。
授权流完成后,用户会被重定向到 Flet 的 OAuth 回调页面(/oauth_callback),该页面会尝试用 JavaScript 关闭浏览器窗口/标签页,并在 JavaScript 关闭失败时指导用户手动关闭。
本节仅适用于 Flet 桌面端和网页端应用,因为移动端的应用内 Web 视图可由 Flet 直接关闭,无需依赖 JavaScript。
你可以在 page.login() 方法中自定义「授权完成」页面的内容,例如:
python
complete_page_html = """
<!DOCTYPE html>
<html>
<head>
<title>Signed in to MyApp</title>
</head>
<body>
<script type="text/javascript">
window.close();
</script>
<p>You've been successfully signed in! You can close this tab or window now.</p>
</body>
</html>
"""
await page.login(
provider,
complete_page_html=complete_page_html,
)你也可以将网页应用改为在同一标签页中打开提供商的授权页,这可能更符合用户习惯,并免去弹窗拦截的麻烦:
python
await page.login(
provider,
on_open_authorization_url=lambda url: ft.UrlLauncher().launch_url(url, web_only_window_name="_self"),
redirect_to_page=True
)要在新标签页中打开流程(注意将 _self 替换为 _blank):
python
await page.login(
provider,
on_open_authorization_url=lambda url: ft.UrlLauncher().launch_url(url, web_only_window_name="_blank")
)配置自定义 OAuth 提供商
你可以使用 flet.auth.oauth_provider.OAuthProvider 类,在应用中配置任何兼容 OAuth 的身份验证提供商。
按照 LinkedIn 授权码流指南 的说明,我们可以获得配置 LinkedIn OAuth 提供商所需的全部参数,从而允许你的 Flet 应用用户用其 LinkedIn 账号登录:
python
import os
import flet
from flet import Button, Page
from flet.auth import OAuthProvider
def main(page: Page):
provider = OAuthProvider(
client_id=os.getenv("LINKEDIN_CLIENT_ID"),
client_secret=os.getenv("LINKEDIN_CLIENT_SECRET"),
authorization_endpoint="https://www.linkedin.com/oauth/v2/authorization",
token_endpoint="https://www.linkedin.com/oauth/v2/accessToken",
user_endpoint="https://api.linkedin.com/v2/me",
user_scopes=["r_liteprofile", "r_emailaddress"],
user_id_fn=lambda u: u["id"],
redirect_url="http://localhost:8550/oauth_callback",
)
async def login_click(e):
await page.login(provider)
async def on_login(e):
if e.error:
raise RuntimeError(e.error)
print("User ID:", page.auth.user.id)
token = await page.auth.get_token()
print("Access token:", token.access_token)
page.on_login = on_login
page.add(Button("Login with LinkedIn", on_click=login_click))
flet.run(main, port=8550, view=flet.AppView.WEB_BROWSER)必填的提供商设置:
client_idclient_secretauthorization_endpointtoken_endpointredirect_url
与其他示例一样,client ID 和 client secret 从环境变量中读取。