使用 OpenID Connect 保护应用程序

本指南介绍如何使用 OpenID Connect (OIDC) 协议将客户端应用程序与 Keycloak 集成。Keycloak 充当 Identity Provider (IdP),并签发由您的应用程序进行验证的令牌。

集成方式

Keycloak 26.x 建议使用标准 OIDC/OAuth 2.0 客户端库,而不是 Keycloak 专用适配器。大多数旧版 Keycloak 适配器(Java、JavaScript、Node.js)已弃用,推荐改用可与任何兼容提供程序协同工作的通用 OIDC 库。

请根据您的应用程序平台选择相应库:

平台推荐库
JavaScript / SPAoidc-client-ts, angular-auth-oidc-client, react-oidc-context
Java / Spring BootSpring Security OAuth2 Client (spring-boot-starter-oauth2-client)
Gocoreos/go-oidc, golang.org/x/oauth2
Pythonauthlib, python-keycloak
Node.jsopenid-client, passport-openidconnect
.NETMicrosoft.AspNetCore.Authentication.OpenIdConnect

前提条件

  • 一个已配置 Realm 的 Keycloak 实例。
  • 在 Keycloak 中注册的 OIDC 客户端(请参见 管理客户端)。

第 1 步:记下 OIDC Discovery URL

每个 Realm 都会公开一个 OIDC discovery endpoint:

https://<keycloak-host>/realms/<realm>/.well-known/openid-configuration

该 endpoint 会返回您的应用程序所需的所有 URL(authorization、token、userinfo、JWKS、logout)。

第 2 步:配置您的应用程序

将以下信息提供给您的 OIDC 库:

参数值
Issuer / Authorityhttps://<keycloak-host>/realms/<realm>
Client ID在 Keycloak 中注册的 client ID
Client Secretclient secret(仅适用于 confidential clients)
Redirect URI在客户端的 Valid redirect URIs 中注册的 URI
Scopesopenid(必需),以及按需使用 profile、email、roles

第 3 步:实现 Authorization Code Flow

对于交互式应用程序,推荐使用 Authorization Code Flow(公共客户端需结合 PKCE)。

流程概览

  1. 您的应用程序将用户重定向到 Keycloak authorization endpoint。
  2. 用户在 Keycloak 进行身份验证。
  3. Keycloak 使用 authorization code 重定向回您的应用程序。
  4. 您的应用程序在 token endpoint 将 code 交换为 token。
  5. 您的应用程序验证 ID token,并使用 access token 调用 API。

Authorization Request

GET https://<keycloak-host>/realms/<realm>/protocol/openid-connect/auth?
  response_type=code&
  client_id=my-app&
  redirect_uri=https://my-app.example.com/callback&
  scope=openid profile email&
  state=<random-state>&
  code_challenge=<PKCE-challenge>&
  code_challenge_method=S256

Token Exchange

curl -s -X POST \
  "https://<keycloak-host>/realms/<realm>/protocol/openid-connect/token" \
  -d "grant_type=authorization_code" \
  -d "code=<authorization-code>" \
  -d "redirect_uri=https://my-app.example.com/callback" \
  -d "client_id=my-app" \
  -d "client_secret=<secret>" \
  -d "code_verifier=<PKCE-verifier>"

Token Response

{
  "access_token": "eyJhbGciOiJSUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 300,
  "refresh_token": "eyJhbGciOiJIUzI1NiIs...",
  "id_token": "eyJhbGciOiJSUzI1NiIs...",
  "scope": "openid profile email"
}

保护 REST API(Resource Server)

对于接收来自其他应用程序的 bearer token 的后端 API:

  1. 在 Keycloak 中注册一个 confidential client,并禁用所有标准 authentication flow(取消选中 Standard flow、Direct access grants 等)。对于 Keycloak 17+ 中的 resource server,这是推荐方法,因为已弃用的 bearer-only client type 不再显示在 Admin Console UI 中。

  2. 配置您的 API 通过 Keycloak JWKS endpoint 验证 access token:

    https://<keycloak-host>/realms/<realm>/protocol/openid-connect/certs
  3. 在每个请求中,提取 Authorization: Bearer <token> header。

  4. 使用 JWKS key 验证 token 签名。

  5. 检查 iss(issuer)、exp(expiration)和 aud(audience)claim。

  6. 使用 token claim(roles、groups)进行 authorization 决策。

退出登录

RP-Initiated Logout

将用户重定向到 Keycloak logout endpoint,以终止 SSO session:

GET https://<keycloak-host>/realms/<realm>/protocol/openid-connect/logout?
  id_token_hint=<id-token>&
  post_logout_redirect_uri=https://my-app.example.com/logged-out&
  client_id=my-app

Back-Channel Logout

对于需要在用户从其他应用程序退出登录时收到通知的应用程序:

  1. 在 client settings 中,将 Backchannel logout URL 设置为您的应用程序 logout endpoint(例如,https://my-app.example.com/backchannel-logout)。
  2. 启用 Backchannel logout session required。
  3. 当用户 session 终止时,Keycloak 会向您的 endpoint 发送一个 logout token (JWT)。

Token Refresh

使用 refresh token 在不重新身份验证的情况下获取新的 access token:

curl -s -X POST \
  "https://<keycloak-host>/realms/<realm>/protocol/openid-connect/token" \
  -d "grant_type=refresh_token" \
  -d "refresh_token=<refresh-token>" \
  -d "client_id=my-app" \
  -d "client_secret=<secret>"

其他 Grant Type

Grant Type使用场景grant_type 值
Client Credentials机器到机器,无用户上下文client_credentials
Device Authorization输入受限设备(IoT、CLI 工具、智能电视)urn:ietf:params:oauth:grant-type:device_code
Token Exchange将一个 token 交换为另一个 token(委托、模拟)urn:ietf:params:oauth:grant-type:token-exchange
已弃用的 Grant Type

Resource Owner Password Credentials (ROPC) grant 虽然受支持,但不建议使用。它会将用户凭据暴露给客户端应用程序,并且无法支持 MFA。请改用 Authorization Code flow。