安全是一个需要深入理解的复杂主题。此外,使用 OAuth 2.0 和 OpenID Connect 规范为基于微服务的复杂系统实现认证和授权更加困难。像 Spring Security 这样的框架和库有助于降低复杂性,但要正确实现 Security 仍然需要经历陡峭的学习曲线。
在本 Spring Security OAuth2 系列教程中,我将与大家分享如何使用 Spring Security OAuth2 为基于微服务的应用实现认证和授权。
有许多身份提供商(Identity Provider)解决方案,如 Keycloak 、Okta 、Auth0 等。在本系列中,我们将使用开源身份和访问管理解决方案 Keycloak。
我不是安全、OAuth2 和 Keycloak 方面的专家。我只是根据自己对这些概念的理解与大家分享我的学习心得。如果你认为其中有任何概念或解释不正确,请指正。
我们不会直接进入 Spring Security OAuth2 的实现,而是先从概念开始学习,循序渐进。
了解 OAuth 2.0 和 OpenID Connect 的基础知识 {#了解-oauth-20-和-openid-connect-的基础知识}
学习 OAuth 2.0 和 OpenID Connect 的第一步是了解一些核心概念,如 OAuth2 中的各种角色(Role)是什么、各种授权方式(Grant Type)是什么以及何时使用哪种方式。
简而言之,在 OAuth2 系统中,有各种不同的组件扮演着不同的角色,也有不同的方法来验证用户身份。
OAuth2.0 角色(Role) {#oauth20-角色role}
- 资源所有者(Resource Owner): 资源所有者通常是终端终用户,他授权应用(客户端)访问他/她的账户。
- 资源服务器(Resource Server): 托管受保护资源的服务器。这是你要访问的 API。
- 客户端(Client): 代表资源所有者请求访问受保护资源的应用(资源所有者正在使用的应用)。
- 授权服务器(Authorization Server): 对资源所有者进行身份验证并在成功授权后发放访问令牌(Access Token)的服务器。
OAuth2.0 授权方式(Grant Type) {#oauth20-授权方式grant-type}
- 授权码模式
- PKCE 授权码模式
- 客户端凭证模式
- 隐式/简化模式(不推荐)
- 资源所有者密码模式(不推荐)
OAuth 2.0 只涉及授权(Authorization),而不涉及身份认证(Authentication)。OpenID Connect 规范是为解决身份认证问题而制定的,它是 OAuth 2.0 的基础层。
在本系列的后续部分中,我们将进一步了解在何时使用哪种授权方式。
安装 Keycloak {#安装-keycloak}
如前所述,我们将使用 Keycloak 来实现基于 OAuth2.0/OpenID Connect 的 Security。
首先使用 docker compose 安装 Keycloak。
version: '3.8'
services:
keycloak:
image: quay.io/keycloak/keycloak:22.0.3
command: ['start-dev']
container_name: keycloak
hostname: keycloak
environment:
- KEYCLOAK_ADMIN=admin
- KEYCLOAK_ADMIN_PASSWORD=admin1234
ports:
- "9191:8080"
启动 Keycloak 容器,如下:
$ docker compose up -d
我们以开发模式启动了 keycloak 容器,并使用环境变量配置了 admin
用户凭证。容器的 8080
端口映射到主机的 9191
端口。
现在你可以通过 http://localhost:9191
访问 Keycloak 管理控制台。
创建 Realm {#创建-realm}
摘自 Keycloak 的文档:
一个 Realm 管理一组用户、凭证、角色和组。用户属于并登录到一个 Realm。Realm 之间相互隔离,只能管理和验证其控制的用户。
你可以创建一个新的 Realm,将一组客户端、用户、角色等与其他客户端、用户、角色等隔离开来。
使用 admin/admin1234
登录管理控制台后,左上角有一个下拉菜单,其中提供了创建新 Realm 的选项。
输入 Realm 名称:sivalabs
,设置 Enabled
为 On
,然后点击 Create
。
创建成功后,应自动选择新 Realm。如果没有,请从下拉菜单中选择 sivalabs
Realm。
创建客户端 {#创建客户端}
要创建新客户端,请点击左侧导航菜单上的 Clients
,然后点击 Create client
按钮。
- General Settings :
- Client type:OpenID Connect
- Client ID:messages-webapp
- Capability config :
- Client authentication:On
- Authorization:Off
- Authentication flow :选中
Standard flow
,取消选中其余复选框
- Login settings :
- Root URL :
http://localhost:8080
- Home URL :
http://localhost:8080
- Valid redirect URIs :
http://localhost:8080/callback
- Valid post logout redirect URIs :
http://localhost:8080
- Web origins :
http://localhost:8080
- Root URL :
使用上述配置创建客户端后,你将进入新创建的客户端 "Settings" 页面。单击 "Credentials" 选项卡并复制 "Client secret" 值。
在本例中,"Client secret" 是:qVcg0foCUNyYbgF0Sg52zeIhLYyOwXpQ.
Keycloak Client AccessType
如果你使用过 Keycloak 的早期版本,你可能会知道有一个名为
AccessType
的选项,其可能的值为public
、confidential
、bearer-only
。在新版本中,没有明确的AccessType
字段。
- 如果 Client authentication 是 Off ,则是公共(public)客户端。
- 如果 Client authentication 是 On ,则是保密(confidential)客户端。
- 如果 Client authentication 是 On ,但是未启用任何 Authentication flow 选项,那么是 Bearer-only 客户端。
现在你可能会问,什么是公开客户端、保密客户端和 Bearer-only 客户端?
- 公共客户端是面向用户的应用,没有服务器后台,如单页应用。它们不能安全地存储任何敏感数据,如 Client secret。
- 保密客户端是在后端服务器上运行的 Web 应用,如 Spring MVC 应用。它们可以安全地存储 Client secret 等敏感数据。
- Bearer-only 客户端通常是仅后台应用(API),它需要调用者提供
access_token
。如果调用者没有提供有效的access_token
,它就会简单地返回Unauthorized
(未授权)响应,而不会启动身份认证流程。
创建用户(User) {#创建用户user}
现在,让我们创建一个用户。点击左侧导航菜单上的 "Users",然后点击 "Add user" 按钮。
创建一个具有以下详细信息的用户:
- Username:siva
- Email :
siva@gmail.com
- Email verified:Yes
- First name:Siva
- Last name:Katamreddy
创建用户后,转到 "Credentials" 选项卡,将 "Password" 设置为 siva1234
,"Temporary" 选项设置为 "Off"。
现在你就可以使用 siva
用户的凭证登录到 sivalabs
Realm 了。
访问 http://localhost:9191/realms/sivalabs/account/
并使用 siva/siva1234
登录。
总结 {#总结}
好了,现在我们已经完成了初始设置,可以开始探索 OAuth 2.0 和 OpenID Connect 了。
在下一篇 Spring Security OAuth 2 教程 - 2:授权码模式 文章中,我们将了解如何通过 "授权码模式"(Authorization Code Flow)获取访问令牌(Access Token)。
参考:https://www.sivalabs.in/spring-security-oauth2-tutorial-introduction/