轻松实现单点登录(SSO):基于 Keycloak 的 OIDC 与 OAuth 2.0 完整指南

言简意赅的讲解Keycloak OIDC 与 OAuth 2.0解决的痛点

Keycloak 是一款开源的身份和访问管理(IAM)工具,支持多种协议,包括 OIDC(OpenID Connect)OAuth 2.0SAML 等。它简化了身份认证与授权流程,提供了集中管理用户、角色、权限等功能,常被用作企业或微服务体系下的统一认证中心。
之前给大家讲解了Keycloak一键登录,后续就有同学发现好像还是不能实现真正SSO。其实真的要实现SSO还是稍微复杂些,本文给大家讲讲OAuth实现的真正的SSO。

1.1 OIDC 与 OAuth 的关系

  • OAuth 2.0:一个授权框架,主要关注“授权”的过程,让第三方应用有权限访问用户在某一服务上的受保护资源。
  • OIDC(OpenID Connect):是基于 OAuth 2.0 的一个身份层(Identity Layer)。也就是说,OIDC 除了完成 OAuth 2.0 的授权能力之外,还额外提供了对用户进行“身份认证”的能力。OIDC 可以让应用获取到更丰富的用户身份信息(如 id_token 中包含的用户信息)。

1.2 为什么 OIDC 登录无法与 OAuth 登录混用

当你在 Keycloak 中配置了 OIDC 流程时,你获得的不仅仅是访问资源的授权,还包含了用户身份信息的校验(id_token 等)。如果你在另一个系统中使用 纯 OAuth 登录,那么该系统关心的更多是令牌用于访问资源的权限验证,可能并不关心用户的具体身份信息格式(或者通过自定义方式来获取),因此它不会自动识别你在 Keycloak 端(OIDC)的认证信息,这就导致需要再次输入用户名和密码进行登录。

常见场景例如:

  • 你在 Keycloak 中使用 OIDC 流程拿到了 id_tokenaccess_token
  • 访问另一个需要 OAuth 2.0 纯授权逻辑的第三方系统时,该系统只接受 OAuth 2.0 标准流程颁发的 access_token(或自家的登录态),由于它无法识别并信任 Keycloak “外部”签发的 token(除非做额外的信任适配),因此会要求再次登录。

二、常用 OAuth 连接参数及示例

Authorization Code Flow(授权码模式)为例,常见的请求示例及参数说明如下:

2.1 获取授权码的请求

HTTP 方法GET
示例 URL(Keycloak 为例):

https://<KEYCLOAK-HOST>/realms/<REALM-NAME>/protocol/openid-connect/auth
  ?client_id=<CLIENT_ID>
  &redirect_uri=<REDIRECT_URI>
  &response_type=code
  &scope=openid profile email
  &state=<RANDOM_STATE>
  • client_id:应用的客户端 ID,在 Keycloak 上注册后获得。
  • redirect_uri:回调地址,用于在授权成功后返回给应用。
  • response_type:典型设置为 code 表示使用授权码模式。
  • scope:权限范围,比如 openid(标识使用 OIDC),profile(基本资料),email(获取邮件地址)等。
  • state:防止 CSRF 攻击的随机字符串,拿到授权码后会原样返回给客户端。

Keycloak oauth2.0 链接参数样例

Keycloak oauth2.0 链接参数样例

2.2 根据授权码获取 Access Token

当用户在 Keycloak 端成功授权后,会将页面重定向回 redirect_uri 并携带 codestate 等参数。然后客户端使用该 code 再向 Keycloak 请求 Access Token:

HTTP 方法POST
URL

https://<KEYCLOAK-HOST>/realms/<REALM-NAME>/protocol/openid-connect/token

请求体(application/x-www-form-urlencoded)

client_id=<CLIENT_ID>
client_secret=<CLIENT_SECRET>
grant_type=authorization_code
code=<AUTHORIZATION_CODE>
redirect_uri=<REDIRECT_URI>
  • client_secret:客户端密钥,机密客户端(Confidential Client)在 Keycloak 上配置生成。
  • grant_type:使用 authorization_code 表示授权码模式。
  • code:上一步得到的授权码。
  • redirect_uri:与申请授权码时的 redirect_uri 必须一致。

返回示例(JSON 格式):

{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.XXXXXX",
  "expires_in": 300,
  "refresh_expires_in": 1800,
  "refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.YYYYYY",
  "token_type": "Bearer",
  "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.ZZZZZZ",
  "not-before-policy": 0,
  "session_state": "e48e5a57-86da-4cf5-8fc4-XXXXXX",
  "scope": "openid profile email"
}

2.3 刷新 Token

HTTP 方法POST
URL

https://<KEYCLOAK-HOST>/realms/<REALM-NAME>/protocol/openid-connect/token

请求体

client_id=<CLIENT_ID>
client_secret=<CLIENT_SECRET>
grant_type=refresh_token
refresh_token=<REFRESH_TOKEN>
  • grant_type:此处使用 refresh_token
  • refresh_token:从上一步获取到的 refresh_token

返回示例与获取 Access Token 类似,主要区别在于新的 access_tokenrefresh_token 会更新。


三、使用接口形式讲解 OAuth 登录

在一些场景下,我们会直接与 Keycloak 的接口进行交互,而不是仅通过浏览器跳转。最常见的就是后端服务或移动端 App 需要对接 Keycloak。以下列举常见的 授权码模式客户端模式 接口交互。

3.1 授权码模式(Authorization Code Flow)接口交互

前提:你的应用或后端已经能够接收浏览器重定向回来的 code

  1. 用户访问前端或后端需要资源

    • 如果后端判断当前用户没有携带有效的 access_token,则引导用户浏览器跳转到 Keycloak 的授权地址,并带上 client_idredirect_uriscope 等参数。
  2. 用户在 Keycloak 登录

    • Keycloak 会展示登录界面,用户输入用户名密码进行验证。
  3. Keycloak 重定向回客户端

    • Keycloak 认证通过后,将浏览器重定向回 redirect_uri,并附带 codestate
  4. 后端(或前端)使用 code 换取令牌

    • 通过 POST 请求到 Keycloak 的 token 接口(上文 2.2)获取 access_tokenrefresh_tokenid_token 等。
  5. 后续访问受保护资源

    • 前端或后端在后续请求中将 access_token 放在 Authorization: Bearer <ACCESS_TOKEN> 请求头中即可访问受保护的 API。

3.2 客户端模式(Client Credentials Flow)接口交互

这种场景下,通常是服务端对服务端的交互,不涉及用户登录界面。例如:一个微服务 A 调用 Keycloak 获取 token,然后使用该 token 去访问另一个受 Keycloak 保护的微服务 B。

  1. 配置 Client Credentials

    • 在 Keycloak 中,为相应的客户端分配 client_idclient_secret
    • 授予该客户端调用目标资源所需的访问范围(Roles/Scope)。
  2. 获取 Access Token

    • 直接通过后端的脚本或代码向 Keycloak 发送 POST 请求:

      POST https://<KEYCLOAK-HOST>/realms/<REALM-NAME>/protocol/openid-connect/token
      Content-Type: application/x-www-form-urlencoded
      
      grant_type=client_credentials
      client_id=<CLIENT_ID>
      client_secret=<CLIENT_SECRET>
      
  3. 使用 Access Token 访问目标资源

    • 将响应中的 access_token 放入请求头 Authorization: Bearer <ACCESS_TOKEN>,即可访问受保护的资源或 API。

四、Keycloak 详细示例:从获取 Token 到查询用户信息

以下以 Keycloak 上的 OIDC 为例,展示如何在拿到 access_token 之后,进一步使用 Token 来查询用户信息等操作。

4.1 获取 Token

参照上文 2.2 的方式,我们在拿到授权码后,通过接口向 Keycloak 交换得到以下令牌:

{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5...",
  "refresh_token": "eyJhbGciOiJSUzI1NiIsInR5...",
  "id_token": "eyJhbGciOiJSUzI1NiIsInR5..."
}

4.2 查询用户信息(User Info Endpoint)

OIDC 规定提供 /userinfo 端点来获取用户的基础信息。在 Keycloak 中,该端点一般如下:

GET https://<KEYCLOAK-HOST>/realms/<REALM-NAME>/protocol/openid-connect/userinfo
Authorization: Bearer <ACCESS_TOKEN>

示例返回

{
  "sub": "245bb7ae-73fc-4def-9d7f-xxxxxx",
  "email_verified": true,
  "name": "John Doe",
  "preferred_username": "johndoe",
  "given_name": "John",
  "family_name": "Doe",
  "email": "john.doe@example.com"
}

4.3 获取用户角色信息

如果你在 Keycloak 中给用户分配了角色(Roles),可在令牌或 /userinfo 接口中获取。如果想要直接在 Access Token 中查看角色信息,需要在 Keycloak 中的 Client ScopesMapper 中配置将角色信息映射到令牌中。

4.4 验证 Token

在后端要验证 Token 时,可以使用 Keycloak 提供的公钥或使用 Keycloak 官方的适配器(Keycloak Adapter)。验证的核心点包括:

  • Token 是否在有效期内(过期时间 exp)。
  • Token 的签名是否正确(需要使用 Keycloak 公钥解密或使用发行者的 JWKS URL 验证)。
  • Token 的 aud(受众)是否与你的应用 client_id 相匹配。
  • Token 的 iss(发行者)是否是你的 Keycloak 实例地址。

五、更多用法

  1. 单点登出(Single Logout)

    • 当用户在客户端进行 Logout 时,可调用 Keycloak 的 Logout 接口,注销全局 Session。
    • URL 通常是:
      GET https://<KEYCLOAK-HOST>/realms/<REALM-NAME>/protocol/openid-connect/logout
        ?id_token_hint=<ID_TOKEN>
        &post_logout_redirect_uri=<REDIRECT_URI>
      
  2. 自定义用户属性

    • 可以在 Keycloak 中给用户添加自定义属性,通过 Mapper 机制映射到 id_tokenaccess_token 中,或者通过 /userinfo 获取。
  3. 多身份源(Identity Brokering)

    • Keycloak 不仅支持本地用户,还能通过身份代理的方式引入其他 IdP(如 GitHub、Google、微软等),但这需要在 Keycloak 端做配置。
    • 如果目标系统只认 OAuth 2.0(而非 OIDC),则仍需额外的映射和适配,否则就会出现需要再次登录的情况。

六、总结

  1. Keycloak 通过支持 OIDCOAuth 2.0,为应用和服务提供了简便的身份认证与授权方案,但要注意 OIDCOAuth 两种场景是有差异的:OIDC 包含身份信息,OAuth 主要面向授权。如同开篇提到的,一旦在 Keycloak 上进行了 OIDC 登录,在一个只支持纯 OAuth 的系统里通常无法复用该登录态,需要再次输入用户名密码。

  2. 典型的 OAuth 连接参数包括 client_idredirect_uriresponse_typescopestate 等,这些参数决定了授权流程的行为。

  3. 通过接口来完成 OAuth 登录,需要先触发授权请求(获取 code),再使用 code 请求 access_token,进而拿到 id_token 等信息后即可进行后续与 Keycloak 的交互,比如获取用户信息、刷新 token 或单点注销等操作。

  4. Keycloak 示例 提供了详细的 /token/userinfo 接口,可演示从零到一如何完成整个认证授权过程,同时可扩展到更多高级功能,如用户角色映射、自定义属性等。

从企业应用到微服务架构,Keycloak 都能作为统一的身份管理中心。当你掌握了 Keycloak 与 OIDC/OAuth 交互的基本模式,也就能够进一步拓展至更多复杂场景,比如多方身份提供商接入、单点登录、单点登出、高级授权策略(基于角色、基于资源服务器的访问控制)等。

希望本篇内容能够帮助你更好地理解 KeycloakOIDCOAuth 领域的应用场景,并为你的应用或服务提供一个更安全、可扩展的用户认证及授权体系。


通过上述内容,你就已经基本理解了这个方法,基础用法我也都有展示。如果你能融会贯通,我相信你会很强

Best
Wenhao (楠博万)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值