Spring Security OAuth 2 教程 - 3:客户端凭证模式

在第二章 “Spring Security OAuth 2 教程 - 2:授权码模式” 中,我们学习了如何通过授权码模式(Authorization Code Flow)对用户进行身份认证。在本文中,我们将了解如何使用客户端凭证模式(Client Credentials Flow),它通常用于服务之间的通信,而无需任何用户(资源所有者)上下文。

客户端凭证模式

有时资源服务器需要在没有任何用户上下文的情况下与另一个资源服务器进行交互。例如,资源服务器 A 可能会运行一个定时任务,该任务将调用资源服务器 B 上的受保护的 REST API 端点。在这些情况下,我们可以通过 “客户端凭证模式” 从授权服务器(Authorization Server)获取访问令牌(access_token)。

创建客户端并启用客户端凭证模式

客户端使用 “客户端凭证模式”,需要启用 “客户端凭证授权支持”。在 Keycloak 中,可以通过启用 Service accounts roles 认证模式来启用 “客户端凭证授权”。

OAuth2 客户端多重授权

OAuth 2.0 客户端可启用多种授权方式,如授权码、客户端凭证、隐式等。

创建一个名为 archival-service 的新客户端。

  • General Settings
    • Client type:OpenID Connect
    • Client ID:archival-service
  • Capability config
    • Client authentication:On
    • Authorization:Off
    • Authentication flow:选中 Service accounts roles,取消选中其余复选框
  • Login settings
    • Root URLhttp://localhost:8282
    • Home URLhttp://localhost:8282

使用上述配置创建客户端后,你将进入新创建的客户端 “Settings” 页面。单击 “Credentials” 选项卡并复制 “Client secret”值。

本例中,Client secretbL1a2V2kouKh4sBMX0UrSmc0d3qubD1a

客户端凭证模式获取 Access Token

我们可以使用以下 cURL 命令,通过客户端凭证模式获取 access_token

curl --location 'http://localhost:9191/realms/sivalabs/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'client_id=archival-service' \
--data-urlencode 'client_secret=bL1a2V2kouKh4sBMX0UrSmc0d3qubD1a'

这将返回类似下面的 JSON 响应:

{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJMeVVPTDg4LVBGM3BYQzFpN3BIeGdFZTJwaWZJY3RyTXJiNklHOElmRTlVIn0.eyJleHAiOjE2OTU1NTU3NjgsImlhdCI6MTY5NTU1NTQ2OCwianRpIjoiZDQwZjEwZjYtMGVjNi00YzAyLWI2ZTktOGE5NzMyYmIwODUzIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo5MTkxL3JlYWxtcy9zaXZhbGFicyIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiIwZjQyYjZkYi0yZWRjLTQyNDUtODAwNC04OWM0Mjg1NDY2MjQiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJhcmNoaXZhbC1zZXJ2aWNlIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vbG9jYWxob3N0OjgyODIiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbImRlZmF1bHQtcm9sZXMtc2l2YWxhYnMiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJjbGllbnRIb3N0IjoiMTkyLjE2OC4xMTcuMSIsInByZWZlcnJlZF91c2VybmFtZSI6InNlcnZpY2UtYWNjb3VudC1hcmNoaXZhbC1zZXJ2aWNlIiwiY2xpZW50QWRkcmVzcyI6IjE5Mi4xNjguMTE3LjEiLCJjbGllbnRfaWQiOiJhcmNoaXZhbC1zZXJ2aWNlIn0.HUjqMP8lxHJfNhxlwtZm8pui_LafuEGf9LxXh5K5tWIQHO6DkfZBWqAhqYggv3mv1QsbRO4akEnldTzrstoFN-4xO_kxKFv10VZLdcUcKf_hhjoySFcKlp0eh1cBRn-C-YyDun5kNOg8kx38G_T7T6F1GMXPAAbMabngmhX2Ke_V4SJZsZvphNu15tmKXnqk8ZUyPRGWSfB9yb19JU79FmiE7RJPMAKSFyV5nHt1HxhSsE7NHeMaqUAn7M5bsQa6em-YxNp3oB2ROA_s0RsACHk41U3d3gARBpZcR2ad2kO0DL_jCV22I2uS4XJCpkvE1MMB5nD6CPwt3Re-8-gGjw",
  "expires_in": 300,
  "refresh_expires_in": 0,
  "token_type": "Bearer",
  "not-before-policy": 0,
  "scope": "email profile"
}

有了 access_token,资源服务器就可以调用另一个资源服务器受保护的 API 端点。

OAuth2 角色和权限

拥有 access_token 并不意味着你可以访问资源服务器上的任何资源。access_token 应具有必要的角色/权限,才能成功调用另一个资源服务器上的 REST API 端点。

我们将在接下来的系列文章中讨论角色和权限。

使用 Postman

我们可以使用 Postman,通过客户端凭证模式获取 access_token 如下:

  • 在 Postman 中打开新请求选项卡
  • 转到 Authorization 选项卡,Type 选择 OAuth 2.0
  • Configure New Token 部分:
    • Grant Type: Client Credentials
    • Access Token URL: http://localhost:9191/realms/sivalabs/protocol/openid-connect/token
    • Client ID: archival-service
    • Client Secret: bL1a2V2kouKh4sBMX0UrSmc0d3qubD1a
    • Scope: openid profile
    • Client Authentication: Send as Basic Auth header
  • 点击 Get New Access Token 按钮
  • 现在你应该可以看到带有 Token 详细信息的响应了

Postman Oauth2 凭证模式的配置

总结

在本文中,我们学习了如何通过 “客户端凭证模式” 获取 access_token,以及如何使用 Postman 完成同样的操作。

在下文中,我们将了解 OAuth 2.0 授权码 + PKCE 模式 的工作原理。


参考:https://www.sivalabs.in/spring-security-oauth2-tutorial-client-credentials-flow/