OIDC 提供商搭建:Keycloak、Okta、Azure AD
聊到 OIDC 的实现,第一步就是选一个靠谱的授权服务器。你可以自己搭,也可以用云服务。我做了几年安全集成,发现很多团队在这步就卡住了——选型不对,后面全是坑。这一节我把三个主流选项的实战经验掏出来说说。
三个选型,先看一张对比表
先别急着搭,把差异搞清楚。
| 维度 | Keycloak | Okta | Azure AD |
|---|---|---|---|
| 部署方式 | 自托管(Docker / WildFly) | SaaS / 云托管 | Azure 云服务 |
| 成本 | 开源免费,基础设施自付 | 按用户/月费,开发版免费 | 随 Azure 订阅,含在身份许可 |
| 特性 | 完整 OIDC / OAuth2,社交登录,用户联盟 | 成熟的企业级策略引擎,自适应 MFA | 与 Microsoft 365 / Entra ID 强绑定,条件访问 |
| 适用场景 | 需要完全控制,离线环境,二次开发 | 追求快速集成,无运维团队 | 企业已有微软生态,需要和 SharePoint / Teams 联动 |
我个人习惯先回答两个问题:要自托管吗? 以及 现有的身份源在哪里? 下面这张图可以直接帮你做决策。
Keycloak 实战:从容器部署到 OIDC 客户端
如果你选 Keycloak,最省事的方式是用官方 Docker 镜像。我在一个离线项目中试过直接解压 WildFly 运行,嗯,能跑,但维护起来真的累。后来全换 Docker Compose 了。
快速部署(生产级)
# docker-compose.yml
version: '3'
services:
keycloak:
image: quay.io/keycloak/keycloak:22.0
command: start --optimized
environment:
KC_HOSTNAME: auth.mydomain.com
KC_HTTPS_CERTIFICATE_FILE: /etc/certs/tls.crt
KC_HTTPS_CERTIFICATE_KEY_FILE: /etc/certs/tls.key
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: ${ADMIN_PW}
KC_DB: postgres
KC_DB_URL_HOST: postgres
KC_DB_URL_DATABASE: keycloak
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: ${DB_PW}
volumes:
- ./certs:/etc/certs
ports:
- 443:8443
部署完后,进 Admin Console 创建 Realm → 创建 Client(选择 openid-connect)→ 配置 Valid Redirect URIs。我习惯把 Access Type 设成 confidential,然后打开 Service Accounts Roles,这样后端服务可以用 client_credentials 拿 。
不要偷懒用 public 模式暴露前端客户端。如果你有 SPA,记得用 PKCE flow,否则你的 client_secret 会在浏览器里裸奔。
Okta 配置:三步搞定 OIDC 应用
Okta 的 SaaS 体验确实好。你先注册一个 Developer 账号(永久免费,但只限 1000 用户)。然后:
- 创建 Application:点 Applications → Add Application → Web 或 Single-Page App。如果你做的是服务端渲染的 Web 应用,选 Web 并用 Authorization Code + PKCE。
- 配置 Grant Types:默认只有 Authorization Code。我建议同时勾上 Refresh ,并设置一个合理的过期窗口(默认 90 天太长了,我改成 7 天)。
- 获取 Issuer 和 Client ID:Okta 会给你一个
https://{你的租户}.okta.com/oauth2/default作为 Issuer。把这个地址配到你的 OIDC 客户端 SDK 里。
我记得有一次遇到一个奇怪的问题:Okta 的登录页面一直跳转回来,报 invalid redirect_uri。查了半天发现是 URI 里多了一个尾部斜杠。Okta 对 redirect_uri 的匹配是严格的。
Okta 的默认 CORS 策略很严格,如果你用 SPA + 自定义域名,务必在 API 设置里显式添加允许的来源。否则用户在第三方浏览器上登录时会直接白屏。
Azure AD:企业生态里的 OIDC 实战
Azure AD(现在叫 Entra ID)是我工作中接触最多的。如果你的公司已经用了 Office 365,那选这个基本不用纠结。但配置时有几个点容易翻车。
| 配置项 | Keycloak / Okta | Azure AD |
|---|---|---|
| 注册应用入口 | Admin Console → Clients | Azure Portal → 应用注册 |
| 平台配置 | 列出所有 redirect_uri | 需要选择平台类型(Web / SPA / 移动) |
| 权限声明 | 默认包含 profile / email / openid | 需要手动添加 Microsoft Graph 权限 |
| 证书与机密 | 支持 client_secret 和 证书 | 推荐使用证书(client_credential) |
我在为一个内部工具集成 Azure AD 时,发现 里居然没有 email 声明。这是因为 Azure AD 默认不会返回 email,除非你在 manifest 里把 optionalClaims 加上。代码示例:
// 在 Azure 应用注册的 manifest 中添加
"optionalClaims": {
"idToken": [
{
"name": "email",
"source": "user"
}
]
}
另外,Azure AD 的 条件访问策略 是它的杀手锏。比如你可以要求从非公司 IP 登录时需要 MFA。但要注意,条件访问策略会影响 获取流程——如果你的后端用 client_credentials 获取 ,那个 里面不会携带用户上下文,条件访问不会触发。我之前踩过这个坑,导致一个后台服务在非公司网络下死活拿不到 。
避坑指南(亲测)
最后说三个我踩得最深的坑,你碰到也能快速定位:
- 端点响应慢——有一次 Keycloak 的 端点要 5 秒才响应。排查发现数据库连接池满了,因为默认连接数只设了 20。生产环境建议调高到 100 以上,并且加连接池监控。
- Okta 的 Rate Limit——免费版每个端点每分钟 600 次请求。我的 CI 流水线并发跑 10 个 Job 同时刷新 ,直接把 IP 给封了。解决方法是给每个 Job 配一个独立的 Okta 应用,或者在 Job 之间加一个 缓存层。
- Azure AD 的 JWT 签名——Azure AD 偶尔会轮换签名密钥(默认 60 天)。如果你在客户端里硬编码了 JWKS URI 的缓存,一旦密钥轮换,你的 验证就会全部失败。我写了一个定时任务每 12 小时重新拉取
/.well-known/openid-configuration。
搭建 OIDC 提供商本身不复杂,真正的工程挑战在于 密钥轮换 和 高可用。下一节我们会专门讲 secret 轮换如何与这些提供商联动。不过那是下一章的事了,先把提供商跑起来再说。
小结:选型看自托管需求、现有生态、运维能力。Keycloak 适合极客控制狂,Okta 适合快速验证,Azure AD 适合微软全家桶。不管你选哪个,先把 的获取和验证跑通,再考虑密钥轮换。