前言
前两篇把 Authentik 部署起来,并配置了 DoraTiger 的登录、注册、MFA 和用户设置流程。接下来补上流程之外的连接:让服务器发邮件,让现有账号通过 Google/Microsoft 登录,以及把系统异常发送给管理员。
这部分遇到的问题比较具体:容器无法访问 Google,OAuth 回调不匹配,外部登录误建账号,收到的品牌邮件顶部图片加载失败。下面按最终配置整理,仍以 2026.8.5 为准,域名和发件账号使用示例。
前置文章:服务器操作指北(12)Authentik 基本概念、默认配置与部署、服务器操作指北(13)Authentik DoraTiger 自建流程与默认配置清理。示例部署目录沿用 /srv/example/authentik,Compose 服务名为 server、worker、postgresql。
各功能的配置位置不同。SMTP 和模板挂载在宿主机部署目录修改;通知传输、匹配策略、规则和身份源在 Authentik 管理员界面创建;Microsoft、Google 的 OAuth 客户端则在各自的云控制台注册。用户的外部账号绑定从 Authentik 用户设置中完成。
本文继续使用 doratiger- 作为对象名称前缀。流程的 Slug、Source 的 Slug 都会进入 URL;阶段、策略、传输和规则表中的名称填入各自的 Name。中文用途放在名称旁说明,避免把标识符与界面字段混在一起。
一、全局 SMTP
1.1 阿里云企业邮箱
本次使用中国内地站点的阿里云企业邮箱,邮箱侧先启用 SMTP 并准备授权码。示例发件地址为 noreply@example.com,接收测试及异常通知的是管理员用户已保存的邮箱。
先在“目录 → 用户”打开管理员账号,确认 Email 字段是实际接收通知的邮箱。发件邮箱 noreply@example.com 配置在 SMTP 中,收件地址来自用户资料,两者不必相同。
登录部署宿主机,在 /srv/example/authentik 中编辑已有 .env,保留原数据库密码和 Authentik 密钥,追加以下配置。阿里云内地站点的 SMTP 主机与 SSL 端口可对照服务商说明:
dotenv12345678AUTHENTIK_EMAIL__HOST=smtp.qiye.aliyun.com AUTHENTIK_EMAIL__PORT=465 AUTHENTIK_EMAIL__USERNAME=noreply@example.com AUTHENTIK_EMAIL__PASSWORD=REPLACE_WITH_SMTP_AUTHORIZATION_CODE AUTHENTIK_EMAIL__USE_TLS=false AUTHENTIK_EMAIL__USE_SSL=true AUTHENTIK_EMAIL__TIMEOUT=30 AUTHENTIK_EMAIL__FROM=DoraTiger Auth <noreply@example.com>
授权码只保存在自己的部署环境中,特殊字符的引用与转义按 Compose 语法处理。邮箱服务商、站点不同,主机和 TLS 参数也可能不同;不要照抄到海外邮箱或其他服务商。
只写 .env 不会自动把任意变量放进容器。第一篇使用共享环境变量锚点,因此还要在 compose.yaml 的 x-authentik-environment 中补上以下键;这是插入片段,不是整份文件:
yaml12345678AUTHENTIK_EMAIL__HOST: ${AUTHENTIK_EMAIL__HOST} AUTHENTIK_EMAIL__PORT: ${AUTHENTIK_EMAIL__PORT} AUTHENTIK_EMAIL__USERNAME: ${AUTHENTIK_EMAIL__USERNAME} AUTHENTIK_EMAIL__PASSWORD: ${AUTHENTIK_EMAIL__PASSWORD} AUTHENTIK_EMAIL__USE_TLS: ${AUTHENTIK_EMAIL__USE_TLS} AUTHENTIK_EMAIL__USE_SSL: ${AUTHENTIK_EMAIL__USE_SSL} AUTHENTIK_EMAIL__TIMEOUT: ${AUTHENTIK_EMAIL__TIMEOUT} AUTHENTIK_EMAIL__FROM: ${AUTHENTIK_EMAIL__FROM}
465 使用隐式 TLS,对应 USE_SSL;587 常见 STARTTLS,对应 USE_TLS。两者不要同时开启。全局 SMTP 在部署配置中设置,UI 的 Email Stage 可以使用自己的 SMTP,但那不会替代系统通知使用的全局配置。官方邮件配置
1.2 应用与验证
在宿主机部署目录执行:
bash1234chmod 600 .env docker compose config -q docker compose up -d --no-deps server worker docker compose exec worker ak test_email admin@example.com
最后一条会真实发送邮件,应换成自己的测试收件地址。先检查收件箱和垃圾邮件,再从实际注册或找回密码流程测试。命令成功、任务入队、SMTP 提交成功和最终收件是不同检查点。
再进入“流程和阶段 → 阶段”,分别编辑注册验证邮件阶段 doratiger-enrollment-email-verification 和密码恢复邮件阶段 doratiger-recovery-email,开启 Use global connection settings 并保存。这样两个阶段都使用部署中的 SMTP 参数,不需要重复填写授权码。
不要连带修改它们的激活行为:注册验证阶段的 Activate user on success 保持开启,密码恢复阶段保持关闭。全局发信测试通过后,再用测试账号分别走一次注册验证和密码恢复,检查收件及链接执行结果。
二、统一邮件品牌模板
2.1 文件与挂载
网页品牌 Logo 不会自动替换所有邮件图片。自定义邮件模板放在 /templates,本例由宿主机 ./custom-templates 挂入 server 和 worker。
这次使用的脱敏模板整理成了附件:邮件模板包。包含 base.html,以及邀请、账号验证、密码恢复、事件通知四组 HTML/TXT 模板;域名统一替换为 auth.example.com,不含账号、邀请令牌和 Logo 图片。
把下载的压缩包放到部署目录,解压后应为:
bash12mkdir -p custom-templates tar -xzf doratiger-mail-templates.tar.gz -C custom-templates
text1234567custom-templates/email/doratiger/ ├── base.html ├── invitation.html / invitation.txt ├── account_confirmation.html / account_confirmation.txt ├── password_reset.html / password_reset.txt ├── event_notification.html / event_notification.txt └── logo.png # 自行放入现有品牌 PNG
先检查并替换模板中的 auth.example.com 为自己的认证域名,再使用。HTML 的用户字段保持 Django 自动转义,链接由 Authentik 提供。HTML 与同名 TXT 一起存在时,可提供 HTML 和纯文本邮件。模板说明
共用模板负责页头、Logo、正文容器和页脚,四种子模板只写各自内容。注册验证和密码恢复不要混用文案:前者继续注册,后者设置新密码。
核对 compose.yaml 中 server 和 worker 的 volumes。沿用基础部署时已经有下面这一项;如果没有,在两个服务的原有列表中各追加一次,不覆盖数据或证书挂载:
yaml1- ./custom-templates:/templates:ro
宿主机的 custom-templates/email/doratiger/invitation.html 因此对应容器内的 /templates/email/doratiger/invitation.html。UI 和策略里的模板名称填写 email/doratiger/invitation.html,不带 /templates/ 前缀。若已有同一目录的挂载,直接保留,不重复添加。
替换域名、放好 Logo 并完成挂载后再重建容器。可以先在部署目录检查文件和模板引用:
bash123test -f custom-templates/email/doratiger/base.html test -f custom-templates/email/doratiger/invitation.html rg -n 'auth\.example\.com|cid:logo' custom-templates/email/doratiger
第一项搜索用于发现尚未替换的示例域名,第二项用于确认内嵌 Logo 引用仍然存在。
2.2 邮件内嵌 Logo
当前版本的邮件发送代码识别正文中的 cid:logo,并从 web/dist/assets/icons/icon_left_brand.png 读取图片作为内嵌附件。于是将共用模板的图片改为:
html12<img src="cid:logo" width="258" alt="DoraTiger Auth" style="display:block;max-width:100%;height:auto;border:0;">
在 server 和 worker 原有 volumes 列表中各追加这一项,其他数据、证书和模板挂载保留:
yaml1- ./custom-templates/email/doratiger/logo.png:/web/dist/assets/icons/icon_left_brand.png:ro
这里利用的是 2026.8.5 的原生 CID 发送机制,但图片路径属于镜像内部实现,不是一个“邮件品牌 Logo”配置项。升级后应复核路径及收件效果。该挂载也会影响其他引用此内嵌 Logo 的邮件。
确认源文件确实是 PNG,再重建应用容器:
bash123test -f custom-templates/email/doratiger/logo.png docker compose config -q docker compose up -d --no-deps server worker
修改后重新发送新邮件,Outlook 和 Gmail 都已确认显示 Logo。旧邮件不会自动随模板更新。
2.3 邮件模板引用
| 使用位置 | Template |
|---|---|
| 管理员邀请策略 | email/doratiger/invitation.html |
doratiger-enrollment-email-verification |
email/doratiger/account_confirmation.html |
doratiger-recovery-email |
email/doratiger/password_reset.html |
| 管理员邮件通知传输 | email/doratiger/event_notification.html |
具体引用需要在各自对象中保存:
- 注册验证:在“流程和阶段 → 阶段”编辑
doratiger-enrollment-email-verification,Template 改为email/doratiger/account_confirmation.html,保留全局 SMTP、有效期和激活设置。 - 密码恢复:编辑
doratiger-recovery-email,Template 改为email/doratiger/password_reset.html,保持 Activate user on success 关闭。 - 管理员通知:编辑邮件通知传输
doratiger-admin-email,在 Template 中选择或填写email/doratiger/event_notification.html。 - 管理员邀请:在邀请表达式策略的
ak_send_email()调用中,将template参数设为email/doratiger/invitation.html。原生邀请页的发信按钮不通过这段自定义策略,不能只改策略就认定所有邀请邮件都会使用同一模板。
对象尚未创建时,在对应创建步骤中填写这个路径即可。保存后发送新邮件检查,不能用收件箱里的旧邮件验证模板更新。
邮件日期用 Asia/Shanghai 显示,标明北京时间;后台日志可能显示 UTC,排查时要转换后比较。品牌模板不改变令牌生成、账号激活或密码验证逻辑。
三、管理员系统通知
通知链路由四个部分组成:事件记录描述发生了什么,Event Matcher 策略筛选事件,通知规则指定接收者和级别,通知传输决定通过邮件还是站内通知送达。登录或异常发生后系统会记录事件,不需要先手工创建一个长期保留的“异常事件”。
3.1 通知传输与事件匹配策略
进入“事件 → 通知传输”,点击创建。先创建邮件传输,Name 填 doratiger-admin-email,Mode 选择 Email,填写主题前缀和模板,关闭 Send once 并保存。再创建站内传输,Name 填 doratiger-admin-local,Mode 选择 authentik inbuilt notifications,同样关闭 Send once。
这两个对象分别是“管理员邮件通道”和“管理员站内通道”,字段汇总如下:
| 名称 | 类型 | 设置 |
|---|---|---|
doratiger-admin-email |
主题前缀 [DoraTiger Auth] ;使用上节事件模板;Send once 关闭 |
|
doratiger-admin-local |
authentik inbuilt notifications | 站内通知;Send once 关闭 |
Send once 不是“同类异常限流”。当前实现启用时会在一个传输的收件人循环中发送一次后停止;要让管理员组每个成员收到通知,保持关闭。
进入“自定义 → 策略”,点击创建,类型选择 Event Matcher(事件匹配器)。以系统异常为例,Name 填 doratiger-match-system-exception,Action 选 system_exception,其他过滤条件留空,保存。依次按下表创建其余策略;一条策略对应一种事件动作,不把多个 Action 拼成一个字符串:
| 策略名称 | Action | 中文用途 |
|---|---|---|
doratiger-match-system-exception |
system_exception |
系统异常 |
doratiger-match-system-task-exception |
system_task_exception |
后台任务异常 |
doratiger-match-policy-exception |
policy_exception |
策略执行异常 |
doratiger-match-property-mapping-exception |
property_mapping_exception |
属性映射异常 |
doratiger-match-configuration-error |
configuration_error |
配置错误 |
doratiger-match-configuration-warning |
configuration_warning |
配置警告 |
doratiger-match-update |
update_available |
可用版本更新 |
3.2 通知规则与收件组
先进入“目录 → 组”确认实际的管理员组及其成员,再在“目录 → 用户”检查这些成员的 Email。这里选择已有管理员组,不新建同名空组,也不因配置收件人而授予新的管理员权限。
在“事件 → 通知规则”点击创建,Name 填下表中的规则名称,Severity 选对应级别。Destination group 选择现有管理员组,Destination event user/Send notification to event user 关闭,Transports 同时选择 doratiger-admin-email 和 doratiger-admin-local,Policy engine mode 选 Any,保存。
| 名称 | 级别 | 绑定策略 |
|---|---|---|
doratiger-notify-system-errors |
Alert | 前五条异常策略,任意一条匹配即可 |
doratiger-notify-configuration-warning |
Warning | 配置警告策略 |
doratiger-notify-update |
Notice | 版本更新策略 |
规则保存后,还需要绑定匹配策略:
- 回到通知规则列表,展开
doratiger-notify-system-errors左侧的箭头,点击“创建或绑定(Create or bind)”。 - 选择“绑定已有策略”,选中
doratiger-match-system-exception,Order 填10,Enabled 开启、Negate 关闭,保存。 - 用同样方式依次绑定后台任务、策略、属性映射异常和配置错误策略,Order 分别填
20、30、40、50。 - 确认系统异常规则的 Policy engine mode 为 Any。一个事件通常只具有一种 Action,这里需要任意一种异常命中即发送,不能要求五种 Action 同时匹配。
- 展开配置警告规则,绑定
doratiger-match-configuration-warning;展开版本更新规则,绑定doratiger-match-update。两条绑定的 Order 均可填10,Enabled 开启、Negate 关闭。
策略绑定在通知规则上,不放进登录流程或 Prompt Stage 的 Validation Policies。保存后逐条展开规则,检查收件组、两个传输和策略绑定都存在。官方通知规则配置
确认管理员用户资料里有正确邮箱。事件是谁触发的,与通知发给谁是两回事;这里固定通知管理员组,不发给每个事件的操作者。
规则没有包含 login_failed 或 email_sent,因此不会把普通输错密码和通知发送成功也当作系统异常。当前逐事件通知,没有合并风暴或同类异常限流。
3.3 测试与默认通知清理
检查时先确认全局 SMTP 测试能够收件,再核对通知规则的配置。触发或遇到符合规则的事件后,按以下顺序查看:
- “事件 → 日志”:找到原始事件,确认 Action 与策略中的值一致。
- 管理员用户的通知列表:检查站内通知是否出现,级别是否符合规则。
- “事件 → 日志”及后台任务:检查对应邮件发送记录或任务失败信息。
- 管理员邮箱:检查实际收件、主题前缀、正文与 Logo。
已有真实错误日志可用于核对事件字段,但不能仅凭旧事件存在就判断新规则已成功发送通知。不要通过故意填错生产数据库或 SMTP 凭据来制造异常。
本次通过一条明确标注测试的配置错误事件检查整条链路,确认生成一条站内通知,并产生对应的 email_sent 记录。邮件采用内嵌品牌 Logo。发送成功事件说明 SMTP 提交完成,实际收件仍需检查邮箱。
验证后停用 Default - Events Transport & Rules 蓝图,删除旧的配置错误、配置警告、异常规则及对应匹配策略。版本更新保留功能,使用上面自建的规则和策略;当所有规则都已使用自建传输时,再删除 default-email-transport 和 default-local-transport。
这套通知依赖 Authentik 和 worker 仍能运行、SMTP 仍能连接。整台服务器停机需要外部监控,不能指望停机的服务给自己发信。
四、Microsoft 个人账号登录
4.1 外部身份认证流程
进入“流程和阶段 → 流程”创建一个供外部身份返回后使用的流程:
| 字段 | 填写内容 |
|---|---|
| Name | DoraTiger 外部身份认证 |
| Slug | doratiger-source-authentication |
| Title | 完成身份验证 |
| Designation | Authentication(认证) |
| Authentication requirement | Require unauthenticated(要求未登录) |
保存后打开“阶段绑定”,两次选择“绑定已有阶段”:Order 10 选择 MFA 验证阶段 doratiger-login-mfa,Order 100 选择会话建立阶段 doratiger-login-session。这两个阶段已经在本地登录配置中创建,不再复制一份。上游 Source 完成身份验证后,该流程继续验证本地 MFA 并建立会话。
在“自定义 → 策略”创建 Expression Policy(表达式策略),Name 填 doratiger-source-authentication-if-sso,Expression 填:
python1return ak_is_sso_flow
保存策略后,返回“DoraTiger 外部身份认证”流程详情,打开“策略/组/用户绑定”,点击创建或绑定,选择已有策略 doratiger-source-authentication-if-sso,Order 填 0,Enabled 开启、Negate 关闭并保存。
这里绑定到整个流程,不绑定到某个阶段,也不放进表单校验。它限定从外部身份认证上下文进入,避免把仅含 MFA 和登录的流程作为任意直接登录入口。直接打开流程 URL 被拒绝不代表配置失败,测试应从 Source 按钮发起。
Google 和 Microsoft 的 Authentication flow 都选择它;Enrollment flow 留空,User matching mode 选择 identifier。本文使用的是登录页 Source 按钮,不是另行把 Source Stage 插入一个外层流程,两种集成的恢复执行机制不能混用。
4.2 Microsoft 应用注册
在 Microsoft Entra 管理中心进入“应用程序 → 应用注册”,点击“新注册”。Name 可填 DoraTiger Auth,用于在微软控制台辨认这个 OAuth 客户端。
Supported account types 要包含个人 Microsoft 账号。本例只允许个人账号登录,按控制台可用选项选择个人账号类型;如果选择“任何组织目录中的账号和个人 Microsoft 账号”,它允许的范围更大,仍需用身份源端点限定本例的登录入口。应用注册需要有相应目录和应用管理权限,个人 Hotmail 邮箱作为登录身份与管理应用注册的权限是两件事。
为应用添加 Web 平台,注册以下回调地址。这里约定 Authentik Source 的 slug 为 microsoft:
text1https://auth.example.com/source/oauth/callback/microsoft/
完成注册后,在 Overview 记录 Application(client)ID。进入“Certificates & secrets → Client secrets → New client secret”,填写用途和有效期,创建后保存密钥的 Value,不是 Secret ID。密钥只在创建时完整显示,到期前需要更换。
在 API permissions 中检查 Microsoft Graph 的委托权限,身份识别使用 openid、profile、email 和 User.Read;本例不同步组织组,不申请 GroupMember.Read.All。组织目录要求管理员同意时,由对应管理员处理;个人账号登录不要照搬组织组同步配置。Authentik Entra OAuth 配置
4.3 Microsoft 身份源
回到 Authentik 管理员界面,进入“目录 → 联合认证与社交登录(Federation and Social login)”,点击创建,类型选择 Entra ID OAuth Source。按表填写:
| 字段 | 填写内容 | 用途 |
|---|---|---|
| Name | Microsoft | 后台和身份源按钮的名称 |
| Slug | microsoft |
必须与微软端回调路径末段一致 |
| Enabled | 开启 | 启用身份源 |
| Consumer key | 微软 Application(client)ID | 标识 OAuth 客户端 |
| Consumer secret | 客户端密钥 Value | 服务端交换令牌时使用 |
| Authentication flow | DoraTiger 外部身份认证 | 选择已创建的自建流程 |
| Enrollment flow | 留空 | 禁止该身份源创建新用户 |
| User matching mode | Use the source-specific identifier | 仅按已建立的外部身份关联匹配 |
Consumer key 和 secret 属于 Protocol settings。展开 URL settings,检查下面的授权和令牌端点,填写后保存,再打开身份源详情核对 Callback URL。
微软端点中的租户部分也要与应用支持的账号类型匹配:
| 端点中的值 | 适用账号 |
|---|---|
consumers |
个人 Microsoft 账号 |
organizations |
工作或学校账号 |
common |
工作或学校账号,以及个人账号;还受应用注册的账号类型限制 |
| 具体租户 ID | 指定组织租户 |
本次最终使用 consumers。对应的授权和令牌端点为:
text12https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize https://login.microsoftonline.com/consumers/oauth2/v2.0/token
用户资料接口使用 https://graph.microsoft.com/v1.0/me,属性映射保留 Entra ID Source 的原生配置;不要为个人账号额外创建组织组映射。common 并不专指个人账号;不能只改端点而忽略应用注册中的账号类型。微软文档对这些取值有具体说明。
4.4 Microsoft 账号绑定
- 先用本地密码和 MFA 登录要绑定的 Authentik 账号,确认当前用户正确。
- 切换到用户界面,进入“Settings → Sources”,找到 Microsoft,点击连接。
- 在微软页面选择自己的个人账号,完成授权并返回 Authentik。
- 在外部身份列表确认 Microsoft 已连接,再用无痕窗口从 Microsoft 登录入口测试。
- 登录后核对用户名和原有权限,并检查用户列表没有新增同邮箱账号。
如果已经误建了用户,先检查外部身份连接归属,再处理解绑和重新绑定,不要直接把新用户升成管理员来掩盖账号重复的问题。本次已经将 Microsoft 身份绑定到原管理员,并关闭了该 Source 的注册流程。
4.5 登录页身份源入口
登录页上的按钮由认证流程中的 Identification Stage 决定。Source 创建成功后,还要把它加入这个阶段的 Sources 列表。这一步不需要编写 Expression Policy。
在管理员界面按以下顺序操作:
- 打开 Flows and Stages → Flows。
- 进入
doratiger-authentication。 - 打开 Stage Bindings,找到
doratiger-login-identification。 - 点击 Edit Stage,在 Source settings → Sources 中把 Microsoft 移到 Selected Sources。Google 创建完成后也在这里添加,保留已经选中的其他身份源。
- 开启 Show source labels,让按钮显示名称,然后保存。
这里编辑的是已绑定的阶段,不需要新建一个同名 Flow,也不需要删除原有的用户名、密码认证阶段。如果使用了自定义 Brand 或认证 Flow,应先确认该入口实际使用的 Flow,再修改其中的 Identification Stage。
保存后打开无痕窗口访问自建登录页:
text1https://auth.example.com/if/flow/doratiger-authentication/
本次 Microsoft 和 Google 都已加入该阶段。匿名访问自建流程时,返回的登录挑战中包含两个身份源入口。自建流程的配置位置也可对照 官方登录页配置说明。
显示按钮只决定入口是否可见,不等于允许注册。 外部身份能否找到本地用户、能否创建新用户,要继续看 Source 自己的匹配模式与注册流程。
五、Google 账号登录
5.1 Google OAuth 客户端
在 Google Cloud Console选择或新建一个项目,确认当前项目正确。进入 Google Auth platform;如果尚未初始化,按引导填写应用信息。在已有配置中,分别检查 Branding、Audience 和 Data Access:Google 同意屏幕配置
| 配置位置 | 填写内容 |
|---|---|
| Branding → App name | DoraTiger Auth |
| User support email、联系邮箱 | 自己可接收通知的邮箱 |
| Authorized domains | 自己控制的域名,示例为 example.com |
| Audience | External,供个人 Google 账号使用 |
| Test users | 测试状态下加入实际参与测试的账号 |
| Data Access | 仅保留登录需要的基本身份信息,不增加 Drive、Gmail 等业务权限 |
旧版控制台从“API 与服务 → OAuth 同意屏幕”进入。下面是 Authentik 官方教程保留的旧版入口截图,不是当前实例的截图;新版对应 Google Auth platform 的配置页面。

同意屏幕配置完成后,在 Clients 中创建 OAuth 客户端;旧版位置为“凭据 → 创建凭据 → OAuth 客户端 ID”。Application type 选择 Web application,Name 可填 DoraTiger Auth,在 Authorized redirect URIs 添加:
text1https://auth.example.com/source/oauth/callback/google/

图中的 authentik.company 是官方示例,本文使用 auth.example.com。回调应填在 Authorized redirect URIs,不填到 Authorized JavaScript origins。保存后记录 Client ID 和 Client Secret,供 Authentik 使用。
5.2 Google 身份源
在 Authentik 的“目录 → 联合认证与社交登录”点击创建,选择 Google OAuth Source,填写:
| 字段 | 填写内容 |
|---|---|
| Name | |
| Slug | google |
| Enabled | 开启 |
| Consumer key | Google OAuth 客户端的 Client ID |
| Consumer secret | 对应的 Client Secret |
| Authentication flow | DoraTiger 外部身份认证(doratiger-source-authentication) |
| Enrollment flow | 留空 |
| User matching mode | Use the source-specific identifier(identifier) |
Google Source 的协议端点和基本身份映射采用原生配置,不额外添加用户名或邮箱自动关联策略。保存后核对 Callback URL 与 Google 客户端完全一致。Google Source 配置
保存及登录过程中,Authentik 服务端需要访问 Google 的发现文档和令牌接口。若容器无法访问,先完成容器出站代理配置并验证网络,再回来保存和测试身份源。浏览器能打开 Google 不能替代这项检查。
5.3 注册限制与账号匹配
创建时就保持 Enrollment flow 为空、匹配模式为 identifier。已有 Google Source 则按下面的方法检查并修改,避免测试匿名登录时创建第二个账号。
在管理员界面打开 Directory → Federation and Social login,编辑 Google OAuth Source。不同语言界面可能将该菜单翻译为“联合认证与社交登录”,需要修改的是 Source 本身。
| 配置项 | 本次设置 | 作用 |
|---|---|---|
| Enabled | 开启 | 保留 Google 身份源可用 |
| Authentication flow | doratiger-source-authentication |
已关联用户完成外部认证后继续登录 |
| Enrollment flow | 清空,不选择任何流程 | 禁止通过这个 Source 注册本地新用户 |
| User matching mode | Use the source-specific identifier(identifier) |
按已建立的来源身份关联识别用户 |
找到 Enrollment flow,移除原来选中的 default-source-enrollment,使这个字段为空,然后保存。这里清空的是 Google Source 对注册流程的引用,不要删除全局的 default-source-enrollment Flow,其他身份源可能仍在使用它。
保留 Authentication flow,并将 User matching mode 设为 identifier。这样,已绑定的 Google 身份通过已有连接找到对应本地用户;未绑定身份不会仅因邮箱相同就自动连到本地账号。
几个容易混淆的匹配选项如下:
| 匹配方式 | 行为与本次取舍 |
|---|---|
identifier |
使用身份源唯一标识及已保存的关联;本次采用 |
email_link |
按相同邮箱自动关联已有用户;本次不采用 |
username_link |
按相同用户名自动关联已有用户;本次不采用 |
email_deny / username_deny |
遇到重复邮箱或用户名时拒绝注册;这不等于关闭所有新用户注册 |
单独清空 Enrollment flow 只控制该身份源的注册路径,不会关闭整个 Authentik 的其他注册入口。也不能只看界面上有没有“注册”按钮来判断是否允许注册。
5.4 Google 账号绑定
采用上述设置后,已有本地账号仍可主动绑定 Google。操作顺序是:
- 先用本地密码登录要绑定的 Authentik 账号,确认当前用户正确。
- 在用户界面进入 Settings → Sources,找到 Google 并选择连接。当前版本的设置入口也可通过
/if/user/#/settings;page-sources进入。 - 跳转到 Google 后选择自己的账号,完成授权并返回 Authentik。
- 在外部身份列表中确认 Google 已连接,再用无痕窗口从登录页测试 Google 登录。
这里验证了本地账号和外部账号两边的身份,随后保存关联。未登录时直接点 Google,是尝试用 Google 登录本地账号,不是给某个指定本地账号添加绑定。
管理员为其他人提供这种登录方式时,应先创建其本地用户,并让用户完成本地登录后自行绑定。不要为了省掉绑定步骤,把 email_link 当作关闭注册的替代方案。若需要进一步限定哪些本地用户可以绑定某个 Source,再单独配置 Source 的策略或组限制;本次没有增加额外的 Expression Policy。
5.5 登录入口与功能验证
进入“流程和阶段 → 阶段”,编辑本地登录识别阶段 doratiger-login-identification,在 Sources 中加入 Google,保留 Microsoft,开启 Show source labels 并保存。Source 的创建和用户绑定都不会自动完成这一步。
按下表分别验证入口、账号归属和注册限制:
| 场景 | 预期结果 |
|---|---|
| 无痕窗口打开自建登录页 | 能看到 Microsoft 和 Google |
| 用已绑定的 Google 账号完成登录 | 回到原来的 Authentik 用户,不创建第二个用户 |
| 用未绑定的 Google 账号在未登录状态下尝试登录 | 因该 Source 未配置注册流程而被拒绝,不创建新用户 |
| 已有本地用户先登录,再从设置连接 Google | 可以建立外部身份关联;仍受该 Source 的访问策略约束 |
本次服务端已确认 Google 的 Enrollment flow 为空、匹配模式为 identifier,自建登录挑战包含 Google,原管理员绑定保持不变。部署版本对未关联身份进入注册分支的处理是返回“Source is not configured for enrollment.”。这项限制来自 Source 配置,无需改写默认注册 Flow 的内部阶段。
Google 和 Microsoft 后续都已完成账号持有人的浏览器登录测试,返回原账号,MFA 也正常。配置检查和入口显示只完成了其中一部分,实际授权仍需分别测试。
六、容器出站代理
6.1 代理服务
最终使用 MetaCubeXD 完整服务端管理 Mihomo,它包含 WebUI、配置管理 Agent 和内核。完整订阅作为远程 Profile 导入,端口、管理密钥等放在独立的本地覆盖 Profile 中,原生刷新间隔设置为 1440 分钟。
完整订阅在 /profiles 页面作为远程 Profile 管理,部署方式见 MetaCubeXD 官方说明。下面以代理服务已经可用为前提,配置 Authentik 与它的连接。
接入 Authentik 前,代理服务应已经运行,能通过所选节点访问 Google。以下示例约定它加入名为 egress-proxy 的 Docker 自定义网络,网络别名也为 egress-proxy,容器内 HTTP 代理端口为 7890。
6.2 共享 Docker 网络
同一自定义网络中的容器可以通过网络别名访问彼此,因此 Authentik 的代理地址直接使用:
text1http://egress-proxy:7890
这条连接不经过宿主机的公开端口,也不需要把代理端口开放到公网。容器之间使用容器监听端口,WebUI 的宿主端口映射与这条连接无关。
这里的网络名和别名是示例约定,不是安装 Mihomo 后自动出现的名称。先检查代理容器加入的 Docker 网络、它在该网络中的别名以及实际 HTTP 监听端口,再将示例中的 egress-proxy 和 7890 替换成一致的值。代理必须允许同网段容器连接;若只监听代理容器自己的回环地址,其他容器仍无法使用。
如果当前部署没有这个外部网络,需要在代理服务的部署配置中建立并加入共享网络、配置别名,再执行 Authentik 的覆盖配置。仅在 Authentik 侧声明 external 网络不会自动把代理容器加入其中。
在 Authentik 部署目录新增 compose.override.yaml。如果已有覆盖文件,应将下面字段合并进去,保留原设置:
yaml1234567891011121314151617181920x-outbound-proxy: &outbound-proxy HTTP_PROXY: http://egress-proxy:7890 HTTPS_PROXY: http://egress-proxy:7890 NO_PROXY: localhost,127.0.0.1,::1,server,worker,postgresql,egress-proxy,auth.example.com,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 http_proxy: http://egress-proxy:7890 https_proxy: http://egress-proxy:7890 no_proxy: localhost,127.0.0.1,::1,server,worker,postgresql,egress-proxy,auth.example.com,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 services: server: environment: *outbound-proxy networks: [default, egress-proxy] worker: environment: *outbound-proxy networks: [default, egress-proxy] networks: egress-proxy: external: true name: egress-proxy
这里保留 default 网络,以继续连接 PostgreSQL;只给 server 和 worker 增加代理网络。HTTPS_PROXY 的值仍以 http:// 开头,表示通过 HTTP 代理的 CONNECT 隧道访问 HTTPS 目标。NO_PROXY 中还应补上自己实际使用的内部域名和网段。
应用配置会重建 server 和 worker,安排在允许短暂中断登录服务时执行:
bash123docker network inspect egress-proxy >/dev/null docker compose config -q docker compose up -d --no-deps server worker
6.3 在 Authentik 容器内验证
测试要放在实际发起请求的容器里。以下命令会使用容器中配置的环境代理:
bash12345678for service in server worker; do docker compose exec -T "$service" python -c ' import requests r = requests.get("https://accounts.google.com/.well-known/openid-configuration", timeout=30) r.raise_for_status() print(r.status_code, r.json()["issuer"]) ' done
本次两个容器均返回 200,issuer 为 https://accounts.google.com;Authentik 的 server、worker 和 PostgreSQL 健康检查也正常。
七、管理员邀请入口
7.1 输入与流程
原生邀请管理能创建邀请,但每次都要填写固定数据 JSON,再点发送邮件。我另外建了一个只供管理员使用的入口,仍在 Authentik 内完成。
先进入“流程和阶段 → 输入”创建受邀邮箱字段:
| 字段 | 值 |
|---|---|
| Name | doratiger-invitation-email |
| Field key | invitation_email |
| Label | 受邀邮箱 |
| Type | |
| Required | 开启 |
| Order | 10 |
| Initial value | 留空 |
再进入“流程和阶段 → 流程”,创建“DoraTiger 发送邀请”,Slug 填 doratiger-send-invitation,Title 填“邀请新用户”,Designation 选 Stage configuration,Authentication requirement 选 Require superuser。
保存后打开阶段绑定,选择“创建并绑定新阶段”,类型选 Prompt,Name 填 doratiger-invitation-recipient-prompt,Fields 只选择刚创建的受邀邮箱输入,绑定 Order 填 10。这时表单已经有了,但尚不能创建邀请;需要保存发信策略并关联到这个表单。
7.2 邀请创建与发信策略
在“自定义 → 策略”点击创建,类型选 Expression Policy,Name 填 doratiger-admin-create-invitation,Expression 填入下面的代码。这里的中文用途是“管理员创建邀请并发送邮件”。
下面是实际策略的脱敏版本。替换 auth.example.com,流程 slug、输入字段键和模板路径需要与前文一致。它会写入邀请并发邮件,不是纯粹的布尔判断,因此专门限制了执行入口。
python123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134import re from datetime import timedelta from uuid import uuid4 from zoneinfo import ZoneInfo from django.core.exceptions import ValidationError from django.core.validators import validate_email from django.db import transaction from django.utils import timezone from django.utils.text import slugify from authentik.core.models import User from authentik.flows.models import Flow from authentik.stages.invitation.models import Invitation http = request.http_request # 只允许管理员在指定流程提交表单时执行。 # 策略测试和 GET 请求不能创建邀请或发信。 if ( request.debug or http is None or http.method != "POST" or http.path != "/api/v3/flows/executor/doratiger-send-invitation/" ): ak_message("请从管理员邀请流程提交邮箱。") return False actor = http.user if not actor.is_authenticated or not actor.is_active or not actor.is_superuser: ak_message("只有超级管理员可以发送邀请。") return False email = ( request.context.get("prompt_data", {}).get("invitation_email") or "" ).strip() try: validate_email(email) except ValidationError: ak_message("请输入有效的邮箱地址。") return False flow = Flow.objects.filter( slug="doratiger-enrollment", designation="enrollment", ).first() if flow is None: ak_message("未找到 doratiger-enrollment 注册流程。") return False if User.objects.filter(email__iexact=email).exists(): ak_message("该邮箱已有账号,请先在用户列表中确认。") return False # 名称只用于识别,去重使用实际邮箱。 # 示例:akadmin-someone-at-gmail-com-20261114-173228-a1b2c3d4 inviter = slugify(actor.username)[:40] or f"user-{actor.pk}" email_label = re.sub( r"[^a-z0-9-]+", "-", email.casefold().replace("@", "-at-"), ).strip("-") # 锁住管理员记录,避免同一管理员并发创建重复邀请。 with transaction.atomic(): User.objects.select_for_update().get(pk=actor.pk) now = timezone.now() existing = Invitation.objects.filter( created_by=actor, flow=flow, fixed_data__email__iexact=email, expires__gt=now, ).first() if existing: ak_message( "该邮箱已有有效邀请,本次未重复发送。" "如需重发,请到“目录 → 邀请”操作。" ) return False timestamp = now.astimezone( ZoneInfo("Asia/Shanghai") ).strftime("%Y%m%d-%H%M%S") short_id = uuid4().hex[:8] name = f"{inviter}-{email_label}-{timestamp}-{short_id}" invitation = Invitation.objects.create( name=name, created_by=actor, flow=flow, single_use=True, expiring=True, expires=now + timedelta(hours=48), fixed_data={"email": email}, ) # 先保存邀请,再提交邮件;失败时保留邀请供检查和重发。 url = ( "https://auth.example.com/if/flow/doratiger-enrollment/" f"?itoken={invitation.pk}" ) try: queued = ak_send_email( address=email, subject="邀请你加入 DoraTiger", template="email/doratiger/invitation.html", context={ "url": url, "expires": invitation.expires, "host": "auth.example.com", }, ) except Exception: ak_message( "邀请已创建,但邮件提交结果不确定。" "请检查系统任务,再从“目录 → 邀请”决定是否重发。" ) return False if not queued: ak_message( "邀请已创建,邮件未成功入队。" "请检查邮件配置,再从“目录 → 邀请”重发。" ) return False ak_message(f"邀请邮件已提交发送:{email}") return True
保存策略后,进入“流程和阶段 → 阶段”,编辑 doratiger-invitation-recipient-prompt,在 Validation Policies 中选择 doratiger-admin-create-invitation 并保存。不要绑定到流程入口,否则执行时还没有提交邮箱。也不要把它复制到其他表单,其 POST 路径检查只允许当前邀请流程。
回到流程详情,确认只有 Order 10 的输入阶段,无需添加 User Write、User Login 或 Redirect 阶段:管理员已经登录,用户账号由受邀者完成注册时才创建。
策略先检查真实 HTTP POST、准确的执行器路径及当前超级管理员身份,拒绝策略测试器和页面 GET 创建邀请。验证邮箱后,再检查该邮箱是否已有账号。
去重以“同一管理员、同一邮箱、同一注册流程、仍有效”为范围,用管理员记录的数据库锁串行处理并发点击。邀请名称采用“邀请人-邮箱标签-北京时间-8 位随机标识”,便于后台辨认;末尾是 UUID 随机片段,并不是邮箱哈希,去重也不依赖名称。
创建的邀请为单次使用、48 小时有效,固定数据为目标邮箱。数据库写入结束后才提交邮件任务。入队失败或结果不确定时保留邀请,管理员到邀请页检查并决定是否重发,不自动创建第二份。
这个策略使用当前版本 Django 模型和执行器路径,属于实例内自定义代码。跨管理员的全局去重、邀请被消耗后继续去重,以及邮件投递和数据库写入的跨系统事务,都不在这段实现范围内。升级后需要重测,不能仅凭策略返回 True 认为收件箱已经收到邮件。
7.3 应用入口与访问策略
进入“应用程序 → 应用程序”,从创建按钮的选项中选择 with existing provider。Name 填“邀请新用户”,Slug 可填 doratiger-invitation,Provider 保持未选择。这里创建的是应用列表中的链接入口,不需要创建 OIDC Provider。
在应用的启动地址(Launch URL)中填写下面的完整地址并保存。应用 Slug 只标识这张入口卡片;地址中的 doratiger-send-invitation 才是刚创建的流程 Slug。
Launch URL 填写:
text1https://auth.example.com/if/flow/doratiger-send-invitation/?next=%2Fif%2Fadmin%2F%23%2Fflow%2Fstages%2Finvitations
在“自定义 → 策略”创建 Expression Policy,Name 填 doratiger-admin-only,用于限制邀请入口仅供超级管理员访问。Expression 填:
python1return request.user.is_authenticated and request.user.is_superuser
保存后返回“邀请新用户”应用详情,打开“策略/组/用户绑定”,点击创建或绑定,选择已有策略 doratiger-admin-only,Order 填 0,Enabled 开启、Negate 关闭。确认没有其他会让普通用户放行的绑定,保存后再回用户界面检查应用卡片。
应用绑定控制入口可见和可访问范围,流程自身还要求超级管理员,写入策略再次检查真实用户。即使知道流程 URL,也不能绕过内部检查。
提交完成后,通过 Launch URL 中的 next 返回原生邀请管理页面。使用正常流程完成后的跳转,不额外添加 Redirect Stage。
7.4 邀请发送验证
用超级管理员打开“邀请新用户”应用,填写一个尚未注册、没有有效重复邀请的测试邮箱并提交。到“目录 → 邀请”确认名称、创建者、注册流程、固定邮箱和 48 小时有效期,再检查收件箱。重复提交同一邮箱,应提示已有有效邀请;普通用户应无法执行这个邀请流程。
随后用未登录窗口打开邮件链接,完成邀请注册、邮箱验证和 MFA。检查新用户的邮箱与邀请一致。若邮件没有收到,先查看邀请是否已经创建,再决定重发;直接重新填写邮箱可能先命中重复邀请检查。
八、验证结果与维护
Microsoft、Google 都已完成绑定和登录测试;邀请创建与发信、注册验证、找回密码已测试成功。Outlook/Gmail 收件 Logo 经过更换内嵌图片后确认正常。管理员异常测试产生了站内通知和邮件发送成功事件,版本更新规则通过了事件匹配检查,没有伪造一个真实更新来证明发布版本存在。
维护时分别检查 OAuth 客户端密钥有效期、SMTP 授权码、后台任务和邮件模板挂载。品牌图片的内部覆盖路径与邀请策略的模型接口都与版本有关,升级后至少重测一次邀请、注册验证和恢复邮件。
默认配置清理按实际替代进度进行:Source 的自建认证流程验证后再停用默认 Source 蓝图,通知验证后再停用默认事件蓝图。最后保留的系统映射和 RBAC 蓝图,作用见第一篇;不要为了清掉默认名称而删除协议基础配置。
九、配置问题与解答
9.1 全局 SMTP 与阶段 SMTP
Q:UI 的邮件阶段可以填写 SMTP,为什么还需要修改部署环境变量?
A: Email Stage 的连接设置只作用于该阶段。系统通知和邀请策略使用的全局邮件连接仍由部署配置提供。本例统一配置全局 SMTP,再让两个 Email Stage 使用全局设置。只修改 .env 也不够,还需确认 Compose 已将变量传给 server 和 worker,并重建容器。
9.2 邮件顶部 Logo 破图
Q:公网图片地址可以访问,为什么 Outlook 和 Gmail 仍显示破图?
A: 本次图片文件完整,IPv4/IPv6 均能返回 PNG,日志也记录到 Gmail 代理成功下载;加版本号仍未解决,不能断言是文件不存在。最终使用原生 cid:logo 内嵌附件,并挂载品牌 PNG 替换镜像对应文件,重新发信后两种邮箱均确认显示。该路径属于版本内部实现,升级时需要复核。
9.3 通知测试事件没有命中规则
Q:日志里有测试事件,为什么系统异常规则没有发送邮件?
A: 先核对 Action、规则绑定的策略、Any 模式、收件组及其成员邮箱,再检查后台任务。当前版本用 Event.new() 直接传字符串 "configuration_error" 会得到 custom_configuration_error,与原生 Action 不同;需要构造原生测试事件时使用 EventAction.CONFIGURATION_ERROR 枚举。普通策略测试通过也不等于整条通知投递链路成功。
9.4 Microsoft 回调地址不匹配
Q:出现 redirect_uri 不合法或未注册的错误,应修改哪里?
A: 对照 Authentik Source 详情显示的 Callback URL,检查 Microsoft 应用注册中的 Web Redirect URI。协议、域名、路径、Source Slug 和末尾斜杠必须对应。https://auth.example.com/ 是站点入口,不是 OAuth 回调;本例回调末段为 /microsoft/。
9.5 外部登录创建了第二个用户
Q:Microsoft 授权成功后,为什么进入了新账号,而不是原管理员?
A: 未登录状态点击身份源按钮是在尝试外部登录。身份尚未绑定且 Source 允许注册时,可能新建本地用户。本例关闭 Enrollment flow,使用 identifier 匹配,先登录原本的本地账号,再从用户设置连接外部身份。误建账号时先核对连接归属,再解绑和重新绑定,不把新账号升为管理员来代替处理。
9.6 Google 发现文档请求超时
Q:浏览器可以打开 Google,为什么保存身份源时仍报连接超时?
A: 浏览器重定向和 Authentik 服务端出站请求不是同一条连接。本次失败目标是 accounts.google.com/.well-known/openid-configuration。应在 server 和 worker 容器内验证请求;需要代理时,检查环境变量、Docker 网络、别名和代理监听端口。两个容器都成功返回发现文档后,再测试实际账号授权。
9.7 完整订阅只加载节点
Q:订阅在桌面客户端包含策略组和规则,为什么放入 proxy-providers 后只剩节点?
A: proxy-providers 只提供节点集合,完整订阅则是包含节点、策略组和规则的 Profile。本次改为完整服务端的远程 Profile,并单独保留本地端口、密钥等覆盖配置。节点更新与完整 Profile 刷新不是一回事。
9.8 邀请入口直接跳转或地址不存在
Q:打开邀请应用时没有邮箱输入框,或跳转后提示 URL 不存在,如何检查?
A: 先检查应用 Launch URL 是否指向 doratiger-send-invitation,而不是直接指向后台邀请列表。流程内只保留邮箱输入阶段,通过正常完成后的 next 跳转,避免旧 Redirect Stage 留下的执行状态。当前邀请管理页为 #/flow/stages/invitations,不是 #/directory/invitations;修改后从新的流程入口重新测试。
9.9 重复邀请与邮件未送达
Q:再次输入邮箱提示重复邀请,但收件箱没有邮件,是否应删除邀请重新创建?
A: 策略先保存邀请,再提交邮件任务,邮件失败时会保留邀请。因此先到邀请页核对有效记录,再查看后台任务和 SMTP 结果,必要时使用重发操作。返回 True 表示提交发送成功,不代表最终投递;重复请求被拒绝也不能证明第一次邮件已经收到。
参考
支付宝
微信