暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

浅谈SpringBoot与Keycloak集成

Share and Fun喜来分 2019-11-22
2504

点击上方蓝字关注我们

全文共1812字,建议阅读用时6分钟。


Keycloak


在一个企业内部往往都需要一个统一的认证和授权系统,一方面可以避免每个应用都开发一套认证和授权功能,另一方面也是实际统一管理企业内部账号和权限的需要。Keycloak 是一个为现代应用系统和服务提供开源的鉴权和授权访问控制管理的开源软件。Keycloak 实现了 OpenID,Auth2.0,SAML 单点登录协议,同时提供 LDAP 和 Active Directory,以及OpenID Connect, SAML2.0,Github,Google 等第三方登录适配功能,能够做到非常简单的开箱即用。鉴于实际上使用最多的是 OpenID Connect 协议,本文也是集中讲解通过 OpenID Connect 协议与 Keycloak 集成。


OpenID Connect 协议


如果要谈单点登录和身份认证,就不得不谈 OpenID Connect (OIDC)。最典型的使用实例就是使用 Google 账户登录其他应用,这一经典的协议模式,为其他厂商的第三方登录起到了标杆的作用,被广泛参考和使用。OpenID Connect 是基于 OAuth 2.0 规范族的可互操作的身份验证协议,可以简单的认为:(身份验证)+ OAuth 2.0 = OpenID Connect。协议中包含各种角色:应用、资源服务器、授权服务器和用户等等。


第三方应用(客户端)


客户端,即尝试去获得用户账号信息的应用,用户需要先对此操作授权。


资源服务器


提供API或资源的访问。


授权服务器


授权服务器用来提供接口,让用户同意或者授权访问请求。Keycloak 则是扮演授权服务器的角色。


用户(资源的拥有者)


资源的拥有者,当前的请求正在尝试获得他们账户的部分信息。


授权模式


OAuth 2.0 提供了多种授权模式(grant types),根据不同的情况而使用。


  • 授权码模式(authorization code):适用于 Web 应用、浏览器应用或是移动 APP;

  • 密码模式(resource owner password credentials):适用于使用用户名和口令登录的模式;

  • 客户端模式(client credentials):适用于第三方客户端应用访问;

  • 简化模式(implicit):简化版的授权码模式,适用于前后端分离的前端应用去获得 token。


Spring Security


开发者的应用如何与 Keycloak 集成?Keycloak 官方提供了丰富的 Adapter 来集成开发,但是在实际开发的过程中我们发现,由于 Keycloak 的社区活跃度非常高,版本更新非常频繁,如果直接使用 Keycloak 的 Adapter 的话,会导致应用跟 Keycloak 的版本耦合度非常高,一旦 Keycloak 需要升级可能会导致应用也需要升级,而如果使用 Spring Security 与 Keycloak 通过 OAuth 2.0 协议集成则可以避免这个问题。截止至发文为止,Keycloak 最新版本为 7.0.0,本文讨论的方法适用于当前 Keycloak 所有版本。


场景实战


首先 SpringBoot 与 Keycloak 集成所需要的 maven 依赖如下:



场景1:开发一个资源服务器程序


资源服务器不关心客服端如何获得 token,只关心客服端的请求是否携带了 token,token 是否合法以及 token 是否有足够的权限。场景的角色与认证流程如图:



首先最重要的代码如下:



最核心的是 @EnableResourceServer 声明,@EnableResourceServer 会触发 Spring Security 过滤器链增加一个 OAuth2AuthenticationProcessingFilter 过滤器从而去提取请求 token 的用户信息和权限。由于 Spring Security 默认的 FixedAuthoritiesExtractor 会去 token 的 payload 当中的 authorities 字段提取权限信息,而 Keycloak 的权限信息则在 realm_access 和 resource_access 字段当中,它们分别代表了 Keycloak 的 Realm Role 和 Client Role 的信息,我们可以使用 Keycloak client 的 mapper 机制将它们的权限信息映射到 authorities,本例中我们使用的 mapper type 是 User Client Role,这样就将用户的 Client Role 信息映射到 authorities,如果使用的 Realm Role 来做权限控制也可以使用 User Realm Role 来做映射:



当然我们也可以自己实现一个 Spring Security 的 AuthoritiesExtractor 接口来个性化提取 token 的权限信息,这里我们选择使用 Keycloak 的字段映射机制。


然后是 SpringBoot 的配置文件 application.yaml:



主要配置的是 Keycloak 的公钥地址,资源服务器用来校验 token 的合法性。


这样一个资源服务器与 Keycloak 的认证授权部分集成就完成了,访问 api 接口的请求就必须携带包含 administrator 权限的 token 。


场景2:开发一个客户端程序


客户端程序工作流程是首先到认证服务器获得一个 token,然后利用这个 token 向资源服务器请求资源。场景的角色与认证流程如图:



这里简单写一个 main 模拟客户端请求服务端接口:



这里主要使用了一个 OAuth2RestTemplate 类,它会负责从认证服务器获取 token 并管理 token 的有效期,简化了客户端程序的认证授权工作,这个例子使用的是客户端认证模式。


场景3:开发一个程序既是资源服务器同时又是客户端程序


这种场景使用的授权码模式 (Authorization Code) 模式,一旦程序检测到请求未进行认证授权则会引导资源拥有者跳转到 Keycloak 登录页面进行登录以获得 token。场景的角色与认证流程如图:



主要代码如下:



然后是 SpringBoot 的配置文件 application.yaml:



这里的核心配置是 @EnableOAuth2Sso 声明, @EnableOAuth2Sso 将我们的程序转化成一个 OAUTH2 客户端程序,它将激活 spring 配置过滤器 OAuth2ClientAuthenticationProcessingFilter 以及其它向认证服务器获得 token 相关的组件。这样在浏览器中一旦访问ui接口则会跳转到 Keycloak 的登录介面。


总结


在文章中我们列举了三种最常见的与 Keycloak 的场景,涉及了资源服务器,第三方应用客户端等角色,也使用了 OAUTH2 的授权码模式,应用访问模式等认证模式。场景中我们使用的权限控制都是通过检查 role 的方式进行的,OAUTH2 协议常用的还有一种通过检查 token 的 Scope 的方式进行权限控制的方式,如果想要使用这种方式则需要自已实现一个 AuthoritiesExtractor 接口从 token 的 scope 字段提取权限信息,这里就不详细展开。相比于使用 Keycloak 的 adapter 集成,使用 Spring Security 去集成 Keycloak 更加轻量和灵活,解耦了与 Keycloak 的版本依赖,同时也是一种比较通用的与认证服务器进行集成的方案。本文是根据本人在后端开发过程的实践工作中总结的一些经验,实际上与 Keycloak 集成还有更多丰富的场景,比如一些前端开发的场景本文并未覆盖到,这里只是抛砖引玉,希望大家可以继续深入的探索。

文章转载自Share and Fun喜来分,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论