使用 authentik 搭建统一身份认证与 OIDC 单点登录实践

发布时间:2026/8/28 18:17:35
使用 authentik 搭建统一身份认证与 OIDC 单点登录实践 在自建应用越来越多之后最容易失控的不是部署而是登录入口。每个应用都维护一套账号密码用户要记住多个密码管理员要处理多次找回密码审计又看不到统一的登录记录。authentik 是解决这类问题的开源身份认证平台identity provider简称 IdP它把认证、授权、用户管理和应用接入集中到一套体系里并为不同应用提供 OIDC、SAML、LDAP 和代理认证等标准化接入方式。这篇文章会围绕 authentik 展开先讲清楚它的定位和核心组件再手把手带你用 Docker Compose 部署一个最小实例创建第一个 OIDC Provider 和应用最后补充关键参数、生产化建议和常见问题排查路径。读完以后你可以用一套 authentik 实例接入多个内部系统实现统一登录和集中管理。1. 先理解 authentik 的定位它不是又一个登录页面很多人第一次接触 authentik 时容易把它理解成“一个带用户管理的登录页”。这个理解太窄了。authentik 真正解决的是应用之间的身份互通问题也就是把“这次登录的用户是谁”这件事从各个应用内部抽出来交给一个独立系统统一判断。1.1 身份认证与单点登录的基本语义先简单梳理几个概念。身份认证Authentication确认用户是谁常见形式是账密、验证码、硬件 Key、WebAuthn。授权Authorization确认用户能做什么比如访问哪些应用、看到哪些数据。单点登录Single Sign-OnSSO用户在一个系统登录后再访问其他接入系统时不需要重复输入密码。authentik 的定位是 IdP它同时承担认证和授权决策的角色。用户在 authentik 里完成登录authentik 记录会话状态然后通过标准协议把“用户已认证”的结果告诉目标应用。应用本身不需要实现找回密码、双因子、账号锁定这些能力只需要信任 authentik 返回的身份信息。这里有一个容易误解的地方SSO 不是说应用不校验权限而是把“如何证明你是你”这件事集中化。应用仍然要自己决定某个用户是否有权限访问某个功能只是不再各自维护一套密码库。1.2 authentik 的核心组件与工作链路authentik 的几个核心概念需要先建立印象Flow流程定义认证过程的步骤例如登录流程、注册流程、找回密码流程。Stage阶段Flow 中的单个步骤例如检查用户是否启用双因子、验证验证码、写入 Cookie。Provider提供方定义如何把认证能力暴露给外部应用比如 OAuth2/OIDC Provider、SAML Provider、LDAP Provider、Proxy Provider。Application应用代表一个需要接入认证业务系统一个 Application 可以绑定一个 Provider。Outpost前哨authentik 提供的轻量组件用于把认证能力延伸到应用侧例如代理认证和 LDAP 服务。一次典型登录链路是这样的用户访问接入应用 A。应用 A 发现用户未登录把浏览器重定向到 authentik 的 OIDC Authorization Endpoint。用户在 authentik 的登录 Flow 中输入账密或完成双因子认证。authentik 确认身份后生成授权码或 Token把用户带回应用 A 的回调地址。应用 A 拿着授权码或 Token 向 authentik 换取用户信息然后建立应用侧会话。这条链路的重点在于只要应用遵循 OIDC 或 SAML 标准接入时不需要关闭原系统只需要改登录方式。1.3 authentik 适用和不适用场景authentik 比较适合以下场景内部多个系统需要统一登录入口。想给已有系统加上 MFA但不想改每个应用的登录代码。需要一个后台管理界面来管理用户、权限和审计日志。自建系统希望通过标准协议接入统一认证而不是被某个商业云服务绑定。它不一定是所有场景的最优解如果你的应用全部是企业微信、钉钉等第三方生态已经天然支持统一认证authentik 可能只是多余一层。如果只是部署一个内部小工具不涉及多应用、多用户和审计要求直接做本地登录更轻量。如果需要复杂组织架构、组织级审批等能力可能要额外开发或选择更重的 IAM 平台。authentik 的核心价值在于让认证体系有唯一事实来源同时保留接入方式的多样性。先建立这个认知后面配置参数时才不会混乱。2. 环境准备部署之前要确认的硬件、端口和目录部署 authentik 并不复杂但准备工作没做好启动后会出现一堆莫名其妙的问题。这里把环境要求、端口规划、目录结构和检查清单一次说清楚。2.1 运行环境与依赖清单authentik 官方推荐使用 Docker Compose 部署核心服务由 PostgreSQL、Redis、authentik server 和 authentik worker 组成。server 负责处理 Web 请求和 APIworker 负责后台任务例如邮件发送、事件处理、过期 token 清理等。学习环境的最低要求可以参考下表生产环境要在此基础上留出冗余项目学习环境建议生产环境建议说明CPU1 核2 核以上worker 和 server 会并行处理任务内存2 GB4 GB 以上Redis 缓存和 Django 进程都会占用内存磁盘10 GB50 GB 以上数据库、媒体文件、日志会持续增长Docker20.1020.10Compose V2 更稳定PostgreSQL由 compose 启动建议独立实例或托管实例生产环境便于备份和故障恢复Redis由 compose 启动建议独立实例或 Sentinel避免容器重启导致会话缓存丢失这里要注意一个区别Docker Compose 启动的 PostgreSQL 和 Redis 适合学习环境和中小规模内部部署生产环境如果对数据可靠性、备份恢复、高可用有更高要求应该把这两个组件独立出来或者使用云厂商的托管实例。2.2 必须提前规划的信息启动之前建议把以下信息确认好否则初始化之后再改很麻烦访问域名例如auth.example.com如果暂时没有域名学习环境可以先用 IP 访问但生产环境必须使用 HTTPS。HTTP 端口默认 9000 用于 HTTP9443 用于 HTTPS可以根据需要映射到宿主机其他端口。数据库密码不能使用默认密码必须单独生成强密码。AUTHENTIK_SECRET_KEY这是 authentik 用于签名和数据加密的密钥必须固定、随机且妥善保管。持久化目录建议放在固定目录下例如/opt/authentik不要把 YAML 和 .env 散落在多个位置。2.3 部署前检查清单这里给出一份可以执行的环境检查清单按顺序在部署前过一遍检查项操作预期结果Docker 是否可用docker versionClient 和 Server 版本正常Compose 是否可用docker compose version能输出版本号目录是否创建mkdir -p /opt/authentik/{media,custom-templates}目录存在端口是否被占用ss -lntp | grep 9000无输出或确认占用进程随机密钥是否生成openssl rand -hex 32输出 64 位十六进制字符串.env 是否已填完整检查必填变量没有空值或占位符注意如果端口 9000 和 9443 已经被其他进程占用不要硬改 compose 里的镜像端口而是通过环境变量或映射端口调整避免破坏容器间通信。3. 使用 Docker Compose 部署 authentik 最小实例部署部分会从零开始先把最小可运行实例跑起来再解释每个配置的作用。3.1 准备目录和变量文件假设统一部署在/opt/authentik先创建目录和 .env 文件。sudo mkdir -p /opt/authentik/{media,custom-templates} cd /opt/authentik sudo touch .env sudo chmod 600 .env.env文件会存放敏感变量把权限收紧到当前用户可读避免其他用户看到密钥。编辑.envAUTHENTIK_VERSION2024.12 AUTHENTIK_SECRET_KEY将这里替换为openssl生成的随机64位字符串 AUTHENTIK_POSTGRESQL__PASSWORD将这里替换为强数据库密码 AUTHENTIK_PORT_HTTP9000 AUTHENTIK_PORT_HTTPS9443生成密钥的命令openssl rand -hex 32注意两点AUTHENTIK_SECRET_KEY一旦用于正式实例不能随意更换否则已经签发的 session 和 token 可能全部失效。AUTHENTIK_POSTGRESQL__PASSWORD是 authentik 连接 PostgreSQL 的密码等会 compose 里的 PostgreSQL 也要用同一个值。3.2 docker-compose.yml 编写说明在/opt/authentik下创建docker-compose.yml。这里使用四个服务PostgreSQL、Redis、server、worker。镜像统一使用ghcr.io/goauthentik/server通过同一个镜像的不同 command 启动 server 和 worker。--- services: postgresql: image: docker.io/library/postgres:16-alpine restart: unless-stopped environment: POSTGRES_DB: authentik POSTGRES_USER: authentik POSTGRES_PASSWORD: ${AUTHENTIK_POSTGRESQL__PASSWORD} volumes: - postgres_data:/var/lib/postgresql/data redis: image: docker.io/library/redis:7-alpine restart: unless-stopped command: --save 60 1 --loglevel warning volumes: - redis_data:/data server: image: ghcr.io/goauthentik/server:${AUTHENTIK_VERSION} restart: unless-stopped command: server ports: - ${AUTHENTIK_PORT_HTTP:-9000}:9000 - ${AUTHENTIK_PORT_HTTPS:-9443}:9443 environment: AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY} AUTHENTIK_POSTGRESQL__HOST: postgresql AUTHENTIK_POSTGRESQL__NAME: authentik AUTHENTIK_POSTGRESQL__USER: authentik AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_POSTGRESQL__PASSWORD} AUTHENTIK_REDIS__HOST: redis volumes: - ./media:/media - ./custom-templates:/templates depends_on: - postgresql - redis worker: image: ghcr.io/goauthentik/server:${AUTHENTIK_VERSION} restart: unless-stopped command: worker environment: AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY} AUTHENTIK_POSTGRESQL__HOST: postgresql AUTHENTIK_POSTGRESQL__NAME: authentik AUTHENTIK_POSTGRESQL__USER: authentik AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_POSTGRESQL__PASSWORD} AUTHENTIK_REDIS__HOST: redis volumes: - ./media:/media - ./custom-templates:/templates depends_on: - postgresql - redis volumes: postgres_data: redis_data:这段配置要做几个解释depends_on只控制容器启动顺序不保证依赖服务已经完全可用。第一次启动时server 可能在 PostgreSQL 初始化完成前就开始连接这是很多“启动失败”现象的根源。AUTHENTIK_POSTGRESQL__HOST使用服务名postgresql这是 Compose 网络内部的 DNS 名称server 容器不需要知道宿主机 IP。media和custom-templates目录使用相对路径挂载要求你在/opt/authentik下执行命令否则会挂载到错误位置。3.3 启动容器并完成初始管理员设置启动命令cd /opt/authentik docker compose up -d查看容器状态docker compose ps正常情况下你会看到四个服务都处于 running 或 healthy 状态。第一次启动会自动执行数据库迁移这一步可能需要几十秒不要刚启动就去看初始化页面。查看日志的命令docker compose logs -f server worker日志里如果出现Listening on或 Django 启动成功相关的输出说明服务已经就绪。然后打开浏览器访问http://localhost:9000/if/flow/initial-setup/这是 authentik 的初始设置流程。按照页面提示创建第一个管理员账号设置用户名和强密码。这一步创建的用户是超级管理员后续所有后台配置都从这个账号进入。完成后访问后台管理界面http://localhost:9000/if/admin/如果能正常进入后台最小实例就部署成功了。注意初始设置流程只能执行一次。如果这一步被跳过或没有完成后面对外访问的登录流程会不正常需要重新检查初始化页面是否可访问。4. 创建第一个 OIDC Provider 和应用部署成功只是第一步。真正实用的操作是把一个外部应用接入 authentik让它通过 OIDC 协议完成登录。4.1 先想清楚应用接入方案在后台点击“创建 Provider”之前先确认你的目标应用支持哪种协议。authentik 支持多种 ProviderProvider 类型适用场景接入难易程度OAuth2/OIDC ProviderWeb 应用、前后端分离应用、移动端标准协议支持面广SAML Provider老牌企业应用、部分 SaaS依赖 XML 配置较繁琐LDAP Provider支持 LDAP 认证的旧系统使用 Outpost 提供 LDAP 服务Proxy Provider没有认证功能的旧 Web 系统通过反代方式加一层登录校验最常用的场景是 OIDC。下面以一个标准 Web 应用为例创建 OIDC Provider 和 Application。4.2 在 authentik 后台创建 Provider登录后台后进入“Applications - Providers”点击“Create”。表单里重点配置以下字段字段含义建议NameProvider 名称写清楚对应应用避免多了之后分不清Client Type客户端类型普通服务端应用选 Confidential纯前端应用选 PublicClient ID / Client Secret客户端凭证可以用默认生成值也可以自定义Redirect URIs授权码回调地址必须填写目标应用实际使用的回调地址Signing Key签名密钥使用默认生成密钥即可生产环境可以单独维护Subject Mode用户唯一标识映射方式根据应用要求选择常见是 User IDRedirect URIs 是最容易出错的字段。这里填的地址必须和目标应用在登录配置里写的回调地址完全一致包括协议、域名和路径。例如应用回调地址是https://app.example.com/callback就不能在 authentik 里填成http://app.example.com/oauth/callback保存 Provider 后页面会显示 Client ID 和 Client Secret。Client Secret 通常不会再次明文展示建议第一时间记录下来写入目标应用的配置。4.3 创建 Application 并把 Provider 绑定到应用进入“Applications - Applications”点击“Create”。配置项包括Name应用在 authentik 后台里的显示名称。Slug应用唯一标识会出现在访问 URL 中。Provider选择刚才创建的 OIDC Provider。保存后这个 Application 就与 Provider 绑定了。目标是应用登录时会跳转到 authentik 对应的 OIDC 地址。在 authentik 中OIDC 常用端点通常遵循以下路径结构具体以你实例的页面跳转链接为准# 授权端点 http://localhost:9000/application/o/authorize/ # Token 端点 http://localhost:9000/application/o/token/ # 用户信息端点 http://localhost:9000/application/o/userinfo/4.4 用最小客户端验证登录流程如果目标应用还没准备好可以用一段简单的 Python 代码验证整个 OIDC 流程是否通。这里提供一个思路性示例不是生产级代码。import requests from urllib.parse import urlencode BASE http://localhost:9000 CLIENT_ID 你的-client-id CLIENT_SECRET 你的-client-secret REDIRECT_URI http://localhost:8000/callback # 1. 构造登录重定向地址 auth_params { client_id: CLIENT_ID, response_type: code, scope: openid email profile, redirect_uri: REDIRECT_URI, } auth_url f{BASE}/application/o/authorize/?{urlencode(auth_params)} print(打开下面的地址完成登录:) print(auth_url) # 2. 浏览器完成登录后会跳转到回调地址并在 URL 上附带 code 参数 # 3. 用 code 向 authentik 换取 token token_resp requests.post( f{BASE}/application/o/token/, data{ grant_type: authorization_code, code: 这里填回调 URL 里的 code, redirect_uri: REDIRECT_URI, }, auth(CLIENT_ID, CLIENT_SECRET), ) print(token_resp.json())这里要注意生产级客户端不能手动拼 URL也不应该把 client secret 放在前端。实际项目中应该使用应用语言对应的 OIDC 客户端库。上面代码的作用是让你理解协议交互的基本流程方便验证 authentik 配置是否正确。5. 关键参数解密这些配置决定了认证体验和生产稳定性authentik 大部分行为由环境变量控制。很多部署问题不是代码问题而是参数配置不符合实际情况。5.1 环境变量速查表环境变量作用默认值错误配置的表现AUTHENTIK_SECRET_KEY加密与签名密钥无重启后会话失效、异常签名错误AUTHENTIK_POSTGRESQL__HOSTPostgreSQL 主机无无法连接数据库AUTHENTIK_POSTGRESQL__NAME数据库名无迁移失败AUTHENTIK_POSTGRESQL__USER数据库用户无权限不足AUTHENTIK_POSTGRESQL__PASSWORD数据库密码无连接拒绝AUTHENTIK_REDIS__HOSTRedis 主机无缓存不可用、登录异常AUTHENTIK_COOKIE__DOMAINCookie 域名空跨子域登录失效AUTHENTIK_BOOTSTRAP_TOKEN初始 token空学习环境可跳过配置里的双下划线表示层级结构。例如AUTHENTIK_POSTGRESQL__HOST对应配置项postgresql.hostAUTHENTIK_REDIS__HOST对应redis.host。这种命名方式在 authentik 环境变量体系里很常见看到双下划线要意识到它是在表示配置层级不是拼写错误。5.2 几个容易被调错的参数AUTHENTIK_SECRET_KEY的作用是签 name 会话、加密数据和派生密钥。它不能为空也不能过短。推荐用 64 位十六进制随机字符串。影响设置后不能随意更改否则已登录用户的 session 会被判断为无效。多个组件之间必须使用同一个密钥否则 server 和 worker 对数据的处理结果会不一致。不要把它提交到 Git 仓库。AUTHENTIK_COOKIE__DOMAIN的作用是控制 authentik 会话 Cookie 的域名范围。影响设置为.example.com后所有子域都可以共享这个 Cookie方便跨应用登录。设置过宽会扩大 Cookie 被串用的风险。如果没有配置域名默认只作用于当前访问主机跨子域登录可能失败。5.3 学习环境与生产环境的差异学习环境只需要关心快速跑通生产环境必须考虑稳定性、安全性和可运维性。层面学习环境生产环境HTTPS可用 HTTP 测试必须使用反向代理或证书终止 TLS数据库Compose 内启动独立实例、定期备份RedisCompose 内启动独立实例、监控内存密钥可随机生成后保存存储在密钥管理系统中限制访问日志查看控制台输出集中采集保留周期内可检索升级可随时重装先备份数据再按版本升级端口暴露宿主机直接映射只暴露反向代理端口生产环境部署时不要直接把 9000 或 9443 暴露到公网。比较好的做法是用 Nginx、Caddy 或云负载均衡只开放 443 端口把请求反向代理到 server 容器的 9000 端口由反向代理终止 HTTPS。注意如果目标是通过公网访问 authentik必须配置 HTTPS。OIDC 和 SAML 协议对回调地址的协议有严格要求HTTP 地址在部分应用库中会被拒绝。6. 常见问题排查从现象倒推根因authentik 部署过程中最常见的报错不复杂但如果没有排查顺序很容易被日志淹没。这里按照现象、原因、检查、解决四步整理。6.1 容器启动失败或反复重启现象执行docker compose up -d后server 容器一直在 restartdocker compose ps显示状态为Restarting。常见原因PostgreSQL 还没初始化完成server 连接被拒绝。.env里的密码与数据库初始化密码不一致。镜像版本不存在或拉取失败。排查顺序docker compose logs server docker compose logs postgresql docker compose ps如果日志显示连接postgresql超时等待几十秒后再看 server 日志。如果日志显示密码验证失败检查.env中AUTHENTIK_POSTGRESQL__PASSWORD是否和POSTGRES_PASSWORD一致。如果版本拉取失败确认AUTHENTIK_VERSION写在.env里且拼写正确。处理建议先执行docker compose down清理容器再重新启动。不要反复restart单个容器否则容易留下脏数据。6.2 初始化页面打不开现象访问http://localhost:9000/if/flow/initial-setup/时 404或页面显示异常。常见原因数据库迁移没有完成。端口映射没有生效。使用了 9443 端口却用 HTTP 协议访问。排查顺序检查容器状态docker compose ps。检查 server 日志是否出现迁移完成标志。确认浏览器地址使用的是 9000 而不是 9443。如果是 9443确认协议是 HTTPS 而不是 HTTP。处理方式确认容器健康后清空浏览器缓存或使用无痕窗口重新访问。如果仍 404查看初始化页面地址是否拼写正确。6.3 应用登录后回调报错现象用户在 authentik 里登录成功后跳回业务应用时白屏或报invalid_client、redirect_uri mismatch。常见原因Redirect URIs与实际回调地址不一致。Client Secret填写错误。应用侧使用了错误的授权端点或 Token 端点。排查顺序先核对 Provider 里的Redirect URIs与业务应用配置里的回调地址逐字符对比。再核对Client ID和Client Secret。查看业务应用日志确认它实际请求的端点和参数。处理建议在 Provider 配置里暂时增加多个候选 Redirect URI 做测试但不建议生产环境长期保留测试地址。6.4 忘记管理员密码或账户被锁定现象管理员账号密码遗忘无法进入后台。常见原因authentik 的账号数据存储在 PostgreSQL 中密码是哈希后的结果不能直接修改数据库字段。处理建议进入 worker 容器执行 authentik 提供的管理命令来创建或重置管理员。具体命令以当前版本官方文档为准不建议直接手改数据库表。docker compose exec worker ak create_admin如果该命令在当前版本中不可用优先查阅对应版本的管理员重置文档。6.5 端口访问和反向代理问题现象容器运行正常通过反向代理域名访问后登录成功但跳转地址变成http://localhost:9000。常见原因authentik 后台的站点 URL 没有配置成对外域名。反向代理没有正确传递X-Forwarded-Proto和X-Forwarded-Host请求头。处理建议在 authentik 的 System Settings 中把外部访问 URL 配置为实际域名例如https://auth.example.com。同时确认 Nginx 配置包含以下请求头proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $host;否则 authentik 可能生成错误的跳转链接。问题现象常见原因检查方式处理建议容器反复重启数据库密码不一致或迁移未完成docker compose logs server统一 .env 密码并清理重启初始化页面 404迁移未完成或端口错误检查容器日志和端口映射等待迁移完成确认协议和端口回调 invalid_clientSecret 或 Redirect URI 不匹配逐字符核对配置修正 Provider 配置登录后跳转错误站点 URL 或反向代理头缺失查看跳转 URL 和 Nginx 日志配置外部 URL 和转发头7. 最佳实践和扩展方向authentik 部署到了生产环境后真正的维护工作才开始。这里列一些可执行的最佳实践以及下一步值得探索的方向。7.1 部署前检查清单每次新建或升级实例前按这份清单检查环境变量是否完整AUTHENTIK_SECRET_KEY和数据库密码是否使用强随机值。.env是否在版本控制之外或者已经加密处理。PostgreSQL 和 Redis 是否有备份方案。端口是否按最小暴露原则开放。外部访问域名是否确定是否已经配置好 HTTPS。是否已经指定持久化目录容器删除后数据不丢失。版本号是否固定是否阅读了对应版本的升级说明。反向代理是否正确传递了 Host 和 X-Forwarded-Proto 请求头。日志是否已经接入集中采集比如 Loki、ELK 或云日志服务。是否创建了普通用户和管理员用户避免所有人员共用超级管理员账号。7.2 生产环境落地的注意点第一条不要把AUTHENTIK_SECRET_KEY写在 docker-compose.yml 里并提交到 Git。建议在部署脚本中从环境变量注入或使用密钥管理工具读取。第二条不要所有系统共用同一个数据库密码。authentik 的数据库账号应该独立分配权限只限定在 authentik 使用的库。第三条升级前必须备份数据库。authentik 升级过程中通常会自动执行迁移但如果迁移中途失败没有备份就很难回滚。第四条多环境部署时让测试环境先执行升级确认没有问题后再升级生产环境。测试环境可以复用同一套配置但密钥和密码必须隔离。第五条不要直接把 9000 端口的 HTTP 服务暴露到公网。即使只是内部系统也建议通过反向代理统一加 TLS避免认证系统自身成为薄弱点。7.3 下一步可以尝试的方向authentik 的扩展能力很强完成基础部署后可以从下面几个方向继续深入为已有旧系统配置 Proxy Provider让没有登录功能的 Web 应用也纳入统一认证。配置 LDAP Provider让支持 LDAP 认证的邮箱、NAS、GitLab 等系统接入 authentik。创建多套 Flow分别用于员工登录、访客注册、管理员审批等不同场景。配置 WebAuthn 硬件密钥或 TOTP 双因子认证提升账号安全性。接入 SAML Provider对接支持 SAML 的企业级应用。在 Kubernetes 环境中使用 Helm Chart 部署并把 authentik 与集群内的 Ingress 整合。对于刚开始接触 authentik 的团队建议先从 OIDC 接入两个真实应用开始把用户创建、登录流程、回调地址、Token 换发这条链路完整跑通。相比一次把所有协议都配齐先把标准模式稳定下来后续增加新的接入方式时会轻松很多。authentik 这类身份认证平台真正的复杂度不在安装而在你能否把认证授权这件事想清楚。配置只是把想清楚的方案翻译成系统设置而已。