之前几篇有关keycloak的文章:
keycloak的介绍和基本概念
Linux服务器使用docker安装keycloak(docker-compose)
使用Docker快速上手Keycloak(官方文档翻译)
先用案例说明:
假设有一个大型企业,该企业使用了多个内部应用程序和服务,包括员工门户、邮箱、人力资源系统、财务系统等。在没有单点登录的情况下,每个应用程序都需要员工单独登录,这会导致以下问题:
用户体验糟糕:员工需要记住多个不同的用户名和密码,并且在每次登录时都需要输入这些凭据,这增加了用户的负担和登录过程的时间。
安全性问题:如果员工为了方便而使用相同或类似的密码,一旦其中一个应用程序被攻破,攻击者可能会访问到其他应用程序,因为相同的凭据可在所有应用程序上使用。
密码管理困难:员工可能会频繁地忘记密码,导致需要重置密码的请求增多,增加了IT部门的工作量。
而单点登录技术就是为了解决这些问题而出现的。
概念
单点登录(Single Sign-On,简称SSO)是一种身份验证和授权机制,允许用户在多个应用程或服务之间使用同一组凭据(例如用户名和密码)进行登录,而不需要在每个应用程序中都输入凭据。使用SSO,用户只需要在一次登录后,即可访问连接到SSO系统的所有其他应用程序,简化了用户体验,提高了安全性,并减少了密码管理的负担。
上述案例中,实施单点登录后,员工只需在第一次访问其中一个应用程序时输入其用户名和密码。之后,当员工访问连接到SSO系统的其他应用程序时,无需再次输入凭据。解决了分别登录出现的问题。
在我之前的文章中,介绍了keycloak中核心的一些概念。
在此,我用思维导图的方式将这些概念进行整合:
keycloak
实现身份与访问的一整套解决方案。具体而言,它是搭建在某台服务器上的一个服务实例,可以通过管理控制台进行管理和配置。
realm 领域
领域是keycloak中专门用来管理项目的工作区,每个Keycloak实例可以包含一个或多个领域,每个领域是一个独立的安全域,不同领域之间的资源相互隔离。领域分为两类,一类是master领域,由Keycloak刚启动时创建,用于管理admin账号以及创建其他的领域;另一类是用户自己创建的普通领域,用于管理具体的项目和用户。
client 客户端
客户端在领域中创建,一个领域可以创建多个客户端,例如一个企业可以创建两个客户端:销售人员客户端、研发人员客户端。在具体的客户端中管理具体的应用程序。
application 应用程序
一个客户端可以配置一至多个应用程序,同一客户端下的多个应用程序可以实现单点登录。一个应用程序可以是SpringBoot应用、JavaScript应用、Android应用等。
adapter 适配器
适配器,用来实现客户端与Keycloak之间的集成。具体而言,同一客户端下的应用共用一个客户端适配器的配置,这也确保了单点登录的实现。
如果对这些概念的关系还是比较生疏,下面通过一个例子进行说明:
假设有一家大型公司,使用keycloak管理用户身份服务,公司系统中的使用者分为客户和员工两大类。系统中有许多应用,则可能的配置如下:
在这个公司系统中,有三个领域,分别是:master、consumer、employee,在employee领域下,存在两个客户端,分别是前台销售客户端和后台管理客户端。
前台销售客户端面向前台销售人员使用,其下有3个应用程序,这三个应用程序可能是使用不同的框架实现的,例如一个使用SpringBoot搭建,另一个使用Node.js。
这3个应用程序有各自的适配器,但每个适配器配置的内容都适配到“前台销售”这个客户端,这样个应用程序就可以实现单点登录了。
关于适配器中配置的具体内容,接下来会提到。
因为仅作为演示,会尽量排除与单点登录无关的配置和操作,集中理解单点登录需要的操作。
步骤:
要实现的效果:
登录其中一个客户端后,另一个客户端不用登录也可访问。
本次演示使用2台主机,一台是云服务器,另一台是本地主机,keycloak部署在云服务器,两个应用分别部署在本地和云服务器。
作为学习,也可所有服务与应用都部署在本地。
详见:Linux服务器使用docker安装keycloak(docker-compose)
所有使用该配置的应用被视为属于这一客户端
点击Download adapter config
下载或记住这一客户端的配置,之后创建应用时使用。
创建第一个应用,名为keycloak_sso_local。
编辑pom.xml
文件
加入依赖配置
<dependencies>
...
<dependency>
<groupId>org.keycloakgroupId>
<artifactId>keycloak-spring-boot-starterartifactId>
dependency>
dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.keycloak.bomgroupId>
<artifactId>keycloak-adapter-bomartifactId>
<version>21.1.1version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
编写controller
@RestController
public class LocalController {
@GetMapping("/")
public String withoutLogin() {
return "未登录可以看到此页面";
}
@GetMapping("/local")
public String login() {
return "您已登录local应用";
}
}
编写application.yml
# 以下配置参考刚才下载的adapter配置(本文4.4部分)
keycloak:
realm: myrealm
auth-server-url: https://xxx.xxx.xxx.xxx:8443/
ssl-required: external
resource: myclient
public-client: true
confidential-port: 0
# 设置以下资源需要登录才能访问
security-constraints:
- auth-roles:
- default-roles-myrealm # 用户创建后的默认角色
security-collections:
- patterns:
- /local/*
编写好后,在本地启动该应用,测试能否访问:
浏览器地址栏输入http://localhost:8080
然后再输入要访问的资源链接http://localhost:8080/local
,此时会重定向到登录页面
跳转到的登录页面的地址是keycloak服务所在的服务器ip/域名。
输入刚才创建的用户名(myuser)和密码,点击登录,登录成功后重定向回localhost(创建领域时配置过)
可以成功访问到http://localhost:8080/local
第一个应用创建成功并能正常运行和访问,接下创建第二个应用。
创建步骤和第一个应用一致,不同的地方:
@GetMapping("/remote")
public String login() {
return "您已登录remote应用";
}
keycloak:
realm: myrealm
auth-server-url: https://xxx.xxx.xxx.xxx:8443/
ssl-required: none # 改成了none
resource: myclient
public-client: true
confidential-port: 0
# 设置以下资源需要登录才能访问
security-constraints:
- auth-roles:
- default-roles-myrealm # 用户创建后的默认角色
security-collections:
- patterns:
- /remote/* # 改成了remote
创建好后,将第二个应用上传到服务器并启动,测试可访问性。
首先在本地和服务器同时启动服务。
然后在本地主机上打开浏览器,分别开启两个窗口,输入对应地址。
接着,在左侧的浏览器地址栏输入路径http://localhost:8080/local
,进行登录。
登录成功后,右侧输入地址http://ip:8080/remote
在非单点的情况下,左侧和右侧需要分别登录,我们成功配置了单点登录,左侧登录成功后,右侧就可以直接访问了,不需要再次登录。
(先右后左同理)
在keycloak控制台的某一具体客户端右上角导出的配置文件,记录了该客户端基本的信息,最重要的信息有3个:
auth-server-url
认证服务地址realm
领域名称resource
客户端名称这三项信息唯一确定了一个客户端,因此,如果2个应用的适配器配置中这三项的配置相同,那么这2个应用就属于同一客户端下的应用,这2个应用之间也就可以实现单点登录。
在SpringBoot项目中,application.yml中关于keycloak的配置,即为应用适配器在SpringBoot应用中的的具体形式,在其他应用中可能是其他形式。
在创建客户端时,设置了2个重定向地址:
这两个地址是在何处起了什么作用?
当一个请求访问本地应用的某个资源(例如/local
这个资源),因为在适配器(application.yml)中配置了该资源需要登录才能访问,而该请求未登录,此时应用会跳转到keycloak的登录页面(适配器中配置了auth-server-url
,应用会通过该配置获取客户端上的详细配置,记载了要跳转的登录页面在哪里),登录成功后,会跳转到某个地址,这里的跳转地址就是我们设置的重定向地址。
如果部署keycloak服务的服务器使用了https,但没有可信的https证书,则会出现该错误,解决方法参考我的另一篇:报错 | PKIX path building failed: …SunCertPathBuilderException:unable to find valid certification…
最好是使用有可信证书的https和域名访问,可以避免许多麻烦。