安装&初始化

下载

只需前往 http://www.keycloak.org/downloads.html ,按需进行下载。

笔者下载的是“Standalone server distribution” 。

安装&启动

安装Keycloak非常简单,步骤如下:

  • 解压下载下来的安装包
  • 将目录切换到KEYCLOAK_PATH/bin ,其中KEYCLOAK_PATH是您Keycloak的根目录
  • 执行./standalone.sh ,即可启动Keycloak,如需后台运行,则执行./standalone.sh &

初始化

启动后,访问http://localhost:8080/ 将会显示类似如图的界面:

该界面让我们创建一个初始化的admin账户。那么我们不妨填写一下,为了测试方便,我们将账号/密码分别设为admin/admin ,然后点击create按钮,将会跳转到如下界面:

由图可知,管理员账户已创建成功,Keycloak初始化也已完成。

管理控制台

点击上图的Administration Console 按钮,将会弹出登录页面:

输入我们之前初始化设置的账号、密码,并点击Login in 按钮,即可登录管理控制台,如下图所示:

由图可知,管理控制台的菜单挺多的,功能也比较丰富,不禁让人有点恐惧——这么多菜单,这么多子功能项,得花多少时间研究啊!没有关系,可以随着笔者的节奏,逐步深入。

与Spring Boot整合

纳尼?上一篇才讲了个初始化,这一篇就与Spring Boot整合啦?这是什么节奏?按照套路,不应该先介绍下这个术语,那个概念吗?

没有关系,Keycloak非常简单,我们可以在实战中了解各种概念。

整合Keycloak非常简单,因为Keycloak为我们提供了各种语言、各种框架的 Adapter ,基于OpenID/SAML协议的Adapter,大概二十多个,有兴趣的可前往:http://www.keycloak.org/docs/latest/securing_apps/index.html#openid-connect-3 阅读。后面等笔者有空了,也会将这些文章翻译出来,敬请期待。

在这里,我们选择OpenID协议中的Spring Boot Adapter ,相关文档:http://www.keycloak.org/docs/latest/securing_apps/index.html#_spring_boot_adapter ,当然,如果你对Spring Security比较熟悉,也可以选用http://www.keycloak.org/docs/latest/securing_apps/index.html#_spring_security_adapter 。不过笔者认为Spring Security过于复杂,用Spring Boot Adapter已经能够完成我们的需求,所以就不搞Spring Security Adapter了。

微服务

假设有一个Spring Boot微服务:

  • 名为:ms-content-sample
  • 首页是http://localhost:8081
  • 它有个路径http://localhost:8081/articles ,只有user-role 角色的用户才能访问,test-role 角色的用户不允许访问。

下面我们来为该服务整合Keycloak,并逐步实现基于Keycloak的单点认证及授权。

准备工作

创建Realm

  • 首先,我们需要创建一个Realm。Realm是一个隔离的概念,Realm A中的用户与Realm B中的用户完全隔离。当然,也可以不创建Realm,直接用 Master 这个Realm,不过一般来说,为了资源的隔离,以及更好的安全性不太建议与管理员共用Realm。如下图所示:

  • 输入Realm名称,这里,如图所示,我们创建了一个名为realm 的Realm。

创建Client

  • 创建完realm后,我们来为ms-content-sample 创建Client ,点击下图的Create按钮。

  • 填写Client信息,这边我们创建一个名为ms-content-sample 的Client。

设置Client

  • 下面我们来配置Client,点击途中的Edit按钮:

  • 设置Client

如图,我们配置了Access Type为public,当然还有其他选项,例如bearer-only,我们先选public,bearer-only我们后面会细讲;配置了Valid Redirect URLS,这是认证成功后跳转到的页面地址,其中我们使用了通配符;配置了Base URL,一般配置成微服务首页即可。

创建角色

比较简单,如图,我们创建了两个角色,user-role 以及test-role

创建用户并分配角色

  • 创建用户

  • 分配角色

如图,点击user-role,并点击Add selected,即可为user1用户分配user-role角色;同理,为user2用户分配test-role角色。

为用户设置登录密码

为Spring Boot微服务整合Keycloak

话不多说,上代码——

基于Spring Boot Adapter的整合步骤如下:

  • 添加依赖管理,引入Keycloak adapter的bom:

    <dependencyManagement><dependencies><dependency><groupId>org.keycloak.bom</groupId><artifactId>keycloak-adapter-bom</artifactId><version>3.4.0.Final</version><type>pom</type><scope>import</scope></dependency></dependencies>
    </dependencyManagement>
    
  • 添加Keycloak的starter:

    <dependency><groupId>org.keycloak</groupId><artifactId>keycloak-spring-boot-starter</artifactId>
    </dependency>
    
  • application.yml 中添加如下配置:

    keycloak:# 表示是一个public的clientpublic-client: true# keycloak的地址auth-server-url: http://localhost:8080/auth# keycloak中的realmrealm: realmresource: ms-content-samplesecurityConstraints:- authRoles:# 以下路径需要user-role角色才能访问- user-rolesecurityCollections:# name可以随便写- name: user-role-mappingspatterns:- /articles
    

    配置项解释详见注释。

  • 这样就整合好Keycloak了。

测试

访问http://localhost:8081/articles ,使用user1 账号登录,发现可以访问;使用user2 账号登录,则会弹出如下界面:

至此,我们已经为Spring Boot应用整合了Keycloak,并且实现了 RBAC 模型的权限控制。

在方法中获得身份、角色等信息

很多场景下,我们希望在Controller中获得当前用户的主体信息,例如获取当前登录的用户名、角色等信息。此时该怎么办呢?

只需添加如下代码:

@GetMapping("/articles")
public HashMap<Object, Object> search(Principal principal) {if (principal instanceof KeycloakPrincipal) {AccessToken accessToken = ((KeycloakPrincipal) principal).getKeycloakSecurityContext().getToken();String preferredUsername = accessToken.getPreferredUsername();AccessToken.Access realmAccess = accessToken.getRealmAccess();Set<String> roles = realmAccess.getRoles();log.info("当前登录用户:{}, 角色:{}", preferredUsername, roles);}

这样,当该方法被请求时,就会打印类似如下的日志:

2017-12-06 14:51:50.963 INFO 3160 — [nio-8081-exec-3] c.i.yes.controller.ArticleController : 当前登录用户:user1, 角色:[user-role, uma_authorization]

是不是非常简单呢?

注销

注销也非常简单只需执行HttpServletRequest.logout() 方法即可注销。

示例代码:

@RestController
public class LogoutController {@GetMapping("/logout")public String logout(HttpServletRequest request) throws ServletException {request.logout();return "退出成功";}
}

邮箱配置

参考下图的配置,即可实现邮件发送。

默认的邮件模板详见 $KEYCLOAK_PATH/themes/base/email/html ,是用Freemarker写的。我们也可以自定义邮件模板,详见“主题定制”一节。

与Spring Cloud整合

经过上文的讲解,我们已实现Keycloak整合Spring Boot应用。那么,在一个使用Spring Cloud构建的分布式应用中,要如何整合Keycloak呢?——即:A微服务信任的Token要如何传递给B微服务呢?

下面我们分两种场景:

  • 使用Feign传递Token
  • 使用Zuul传递Token

使用Feign传递Token

下面我们创建一个新的微服务ms-consumer-sample ,该微服务使用Feign调用上文的http://localhost:8081/articles 接口。

按照前文整合Spring Boot的步骤,在相同Realm中,创建一个新的Client,名为ms-consumer-sample ,然后为ms-consumer-sample 微服务也整合Keycloak。下面我们使用Feign实现Token的传递:

只需编写一个Feign拦截器:

public class KeycloakRequestInterceptor implements RequestInterceptor {private static final String AUTHORIZATION_HEADER = "Authorization";@Overridepublic void apply(RequestTemplate template) {ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();Principal principal = attributes.getRequest().getUserPrincipal();if (principal != null && principal instanceof KeycloakPrincipal) {KeycloakSecurityContext keycloakSecurityContext = ((KeycloakPrincipal) principal).getKeycloakSecurityContext();if (keycloakSecurityContext instanceof RefreshableKeycloakSecurityContext) {RefreshableKeycloakSecurityContext.class.cast(keycloakSecurityContext).refreshExpiredToken(true);template.header(AUTHORIZATION_HEADER, "Bearer " + keycloakSecurityContext.getTokenString());}}// 否则啥都不干}
}

由该拦截器代码不难看出,我们把自己接收的Token,放到Header中,传递给服务提供者(即:ms-content-sample) 。

这样,我们就实现了ms-consumer-sample 以及ms-content-sample 两个微服务之间的Token传递——即:单点登录

使用Zuul传递Token

在Spring Cloud构建的应用中,往往使用Zuul作为对外服务的入口,架构图如下:

此时,我们希望达到:在Zuul微服务上达到统一认证的效果——即:在Zuul上登录,就相当于登录了所有微服务。

要怎么办呢?这个问题,其实就是:Zuul信任的Token要如何传递给Zuul所代理的微服务呢?

我们创建一个新的client,名为zuul-server ,然后编写一个Zuul过滤器:

@Component
public class KeycloakRouteZuulFilter extends ZuulFilter {private static final String AUTHORIZATION_HEADER = "Authorization";@Overridepublic String filterType() {return FilterConstants.ROUTE_TYPE;}@Overridepublic int filterOrder() {return 1;}@Overridepublic boolean shouldFilter() {RequestContext ctx = RequestContext.getCurrentContext();HttpServletRequest request = ctx.getRequest();Principal principal = request.getUserPrincipal();return principal != null && principal instanceof KeycloakPrincipal;}@Overridepublic Object run() {RequestContext ctx = RequestContext.getCurrentContext();if (ctx.getRequest().getHeader(AUTHORIZATION_HEADER) == null) {this.addKeycloakTokenToHeader(ctx);}return null;}private void addKeycloakTokenToHeader(RequestContext ctx) {Principal principal = ctx.getRequest().getUserPrincipal();// 这里之所以可以直接强制转换,是因为shouldFilter中已经做了类型判断。KeycloakSecurityContext keycloakSecurityContext = ((KeycloakPrincipal) principal).getKeycloakSecurityContext();if (keycloakSecurityContext instanceof RefreshableKeycloakSecurityContext) {ctx.addZuulRequestHeader(AUTHORIZATION_HEADER,this.buildBearerToken((RefreshableKeycloakSecurityContext) keycloakSecurityContext));}// 用户没有登录,啥都不干}private String buildBearerToken(RefreshableKeycloakSecurityContext securityContext) {return "Bearer " + securityContext.getTokenString();}
}

由代码可知,我们在该过滤器中实现了Token的传递。

代码详见ms-consumer-sample

配置改进

上文,我们创建的Client都是public 类型的,而现在,其实只有Zuul需要对外,其他服务都是经过Zuul或者Feign传递Token的。因此,我们可将除Zuul以外的所有Client的Access Type统统改为bearer-only ,如图所示:

代码详见zuul-server

登录相关配置

前文中,我们是自己添加用户的,现实中,用户往往是注册的;另外,如果我想实现Remember Me 的功能该怎么办呢?难道这一切都需要自己编码吗?显然不需要!只需按需在下图中配置即可:

例如,我们想实现用户注册,只需将User registration勾选即可。这样登录页面就会变成类似下图:

主题定制

Keycloak自带的届满稍微有那么一点丑陋,但Keycloak允许我们自定义主题——

开发好主题后,将主题目录复制到$KEYCLOAK_PATH/themes 目录中即可。Keycloak默认为我们准备了两套主题,如下图:

我们可参考这两套主题的代码,编写我们自己的主题。主题定制比较简单,是用Freemarker搞的。万能GitHub上也有一些主题,只需要搜 keycloak theme 即可找到。个别主题还是不错的。

第三方认证

很多网站有QQ登录、GitHub登录、新浪微博登录等第三方认证按钮。如果我们也想实现第三方认证该怎么办呢?Keycloak也具备这样的能力!下面笔者以GitHub登录为例,为我们的应用实现使用GitHub账号登录的能力!

  • 在Keycloak管理控制台上按下图操作:

  • 将会看到类似如下的界面,在这个页面上,Client ID以及Client Secret是必填项,如何获得这两项的值呢?

  • 登录GitHub,访问 https://github.com/settings/profile ,点击左侧的 Developer settings 按钮,将会看到类似如下的界面:

  • 点击New OAuth App 按钮,将会看到类似于如下的界面:

  • 点击Register application按钮后,即可看到该应用的Client ID以及Client Secret。

  • 回到Keycloak管理控制台,填入获得的Client ID以及Client Secret。

  • 下面,我们来为GitHub用户分配角色。点击下图中的Edit按钮:

  • 将会看到类似如下的界面。点击右侧的Create:

  • 将会看到类似如下的界面。按照下图填写信息,其中Name随意,建议设置一个人类可读的名称即可。

测试

  • 注销后,重新访问任意一个需要登录的URL,将会看到类似如下的界面:

由图可知,激动人心的GitHub登录按钮已经出现了。

  • 访问 http://zuul/ms-content-sample/articles ,该地址需要user-role角色才能访问。如果可正常访问。说明配置成功。

术语

在继续之前,了解Keycloak Authorization Service引入的术语和概念非常重要。

Resource Server(资源服务器)

根据OAuth2术语,resource server是托管受保护资源并能够接受和响应受保护资源请求的服务器。

resource server通常依靠某种信息来决定是否允许访问受保护的资源。对于基于RESTful的resource server,该信息通常在security token中携带,通常作为bearer token,连同对服务器的每个请求一起发送。依靠会话来验证用户的Web应用程序通常将该信息存储在用户的会话中,并从那里为每个请求进行检索。

在Keycloak中,任何confidential client应用都可充当resource server。此client的资源和各自的scope受到一组authorization policy的保护和管理。

Resource(资源)

resource是应用和组织的资产的一部分。它可以是一组端点,一个经典的网页资源,如HTML页面等。在authorization policy术语中,资源是受保护的对象。

每个resource都有唯一的标识符,可用来表示单个或一组资源。例如,您可以管理一个Banking Account Resource,该resource会为所有银行账户定义一组authorization policy。但是,您也可拥有一个名为Alice’s Banking Account的资源,这个resource代表一个客户拥有的单一resource,它也可拥有自己的一组authorization policy。

Scope

resource的scope是可在resource上执行的有限的访问范围。在authorization policy术语中,scope是逻辑上可应用于resource的潜在的动词之一。

它通常表示对于给定的resource,能做些什么。scope的例子是查看、编辑、删除等。但是,scope也可与资源提供的特定信息相关。在这种情况下,您可以拥有project resource和cost scope,其中cost scope用于定义用户访问项目cost的特定策略和权限。

Permission(权限)

想想这个简单和非常普遍的permission:

permission将受保护的对象与必须评估的policy关联起来,以确定是否授予访问权限。

X CAN DO Y ON RESOURCE Z

where …​

X表示一个或多个用户,角色或group,或者它们的组合。也可在这里使用声明和上下文。

Y表示要执行的动作,例如写入、查看等。

Z表示受保护的资源,例如“/accounts”。

Keycloak提供了一个丰富的平台,用于构建从简单到非常复杂、基于规则的动态权限等一系列permission strategy。它提供了灵活性,并有助于:

减少代码重构和权限管理成本

支持更灵活的安全模式,帮助您轻松适应安全需求的变化

在运行时进行更改;应用程序只关心受保护的resource和scope,而无需关心它们如何受到保护。

Policy(策略)

policy定义了授予访问对象必须满足的条件。与permission不同,您无需指定受保护的对象,而是指定访问给定对象(例如,resource、scope或两者)时必须满足的条件。policy与可用于保护资源的、不同的访问控制机制(access control mechanisms:ACM)密切相关。通过policy,您可实施基于属性的访问控制(attribute-based access control:ABAC),基于角色的访问控制(role-based access control:RBAC),基于上下文的访问控制(context-based access control)或这些的任意组合的策略。

Keycloak利用policy的概念,以及如何通过提供聚合policy的概念来定义它们,您可以在其中构建“policy 中的 policy”,并仍然控制评估的行为。 Keycloak Authorization Service中的policy实施遵循分而治之的技术,而不是写出一个满足访问给定resource必须满足的所有条件的大型policy。也就是说,您可创建单独的policy,然后与不同的permission重用它们,并通过组合各个policy构建更复杂的policy。

Policy Provider(策略提供者)

Policy Provider是特定policy类型的实现。Keycloak提供内置的Policy,由相应的Policy Provider支持,您可以创建自己的Policy类型来支持您的特定需求。

Keycloak提供了一个SPI(Service Provider Interface:服务提供者接口),您可以使用它来插入自己的策Service Provider实现。

Permission Ticket(许可签名)

Permission Ticket是由OAuth2的用户管理访问( OAuth2’s User-Managed Access (UMA) Profile :UMA)配置文件规范定义的一种特殊类型的token,它提供了一种由authorization server确定的不透明结构。该结构表示客户请求的resource和/或scope,以及必须应用于授权数据请求(请求方令牌requesting party token:[RPT])的policy。

在UMA中,Permission Ticket对于支持人与人之间的共享以及人与组织之间的共享至关重要。为authorization workflow使用permission ticket可实现从简单到复杂的一系列场景,其中resource owner和resource server基于对这些resource访问的细粒度策略完全控制其资源。

在UMA workflow中,authorization server向resource server发出permission ticket,resource server将permission ticket返回给试图访问受保护资源的client。一旦client收到ticket,它就可通过将ticket发送回authorization server来请求RPT(持有authorization数据的最后一个令牌)。

有关permission ticket的更多信息,请参阅 Authorization API 和 UMA 规范。

参考文档

http://slackspace.de/articles/authentication-with-spring-boot-angularjs-and-keycloak/

TODO

keycloak ha
高可用

权限控制,先了解下术语:http://www.keycloak.org/docs/latest/authorization_services/index.html#_overview_terminology_resource_server

spring boot 的auth-role不能有通配符,这是个bug:https://issues.jboss.org/browse/KEYCLOAK-5775
等该bug修复后,考虑将用例改成完全动态控制。
大致方法是:将/* 设成 role=*,任意角色均可访问;
然后,在keycloak中,开启授权。并配置各个路径需要什么角色/权限才能访问
参考:https://github.com/keycloak/keycloak-quickstarts/tree/latest/app-authz-springboot

Keycloak详细教程相关推荐

  1. 手把手从零开始搭建k8s集群超详细教程

    本教程根据B站课程云原生Java架构师的第一课K8s+Docker+KubeSphere+DevOps同步所做笔记教程 k8s集群搭建超详细教程 1. 基本环境搭建 1. 创建私有网络 2. 创建服务 ...

  2. win10系统优化计算机,全面优化win10电脑系统详细教程 | 专业网吧维护

    全面优化win10电脑系统详细教程 以下针对win10系统的电脑全面优化的步骤: 步骤1:禁止开机启动项 1.首先我们先来优化开机速度,拖慢开机速度的首先是开机自启动项,Ctrl + Shift + ...

  3. GPU运行Tensorflow详细教程及错误解决

    GPU运行Tensorflow详细教程及错误解决 前提条件 配置GPU运行 确认是否成功配置 出现的错误及解决方案 前提条件 最重要的一点:CUDA与tensorflow的版本一点要对应,不然用不了! ...

  4. VMware虚拟机安装黑苹果MacOS Mojave系统详细教程

    更多资源请百度搜索:前端资源网 欢迎关注我的博客:www.w3h5.com 最近遇到一个H5页面的 iPhone X 刘海兼容问题.查到一个 XCode 编辑器,可以模拟 iPhone X 环境运行. ...

  5. [分享] 从定制Win7母盘到封装详细教程 By BILL ( 10月23日补充说明 )

    [分享] 从定制Win7母盘到封装详细教程 By BILL ( 10月23日补充说明 ) billcheung 发表于 2011-10-23 00:07:49 https://www.itsk.com ...

  6. win七系统如何卸载MySQL_win7系统卸载SQL2008R2数据库的详细教程

    用过SQL2008R2数据库的朋友都知道,安装起来容易卸起来麻烦,可是在win7 32位旗舰版系统就不知道怎么卸载SQL2008R2数据库了.其实卸载SQL2008R2数据库的方法也很简单,可直接通过 ...

  7. Ubuntu系统安装搜狗输入法详细教程

    Ubuntu16.04系统安装搜狗输入法详细教程 解决Ubuntu 18.04中文输入法的问题,安装搜狗拼音

  8. PHP7Grafika,PHP图片处理库Grafika详细教程(3):图像属性处理

    该文章是接着上篇文章,<PHP极其强大的图片处理库Grafika详细教程(2):图像特效处理模块>,由于grafika功能太多,所以分开写,其他的点击这里 该文章主要写grafika的图像 ...

  9. mysql.msi卸载_MySql安装与卸载的详细教程

    本文为大家分享了MySql安装与卸载的教程,供大家参考,具体内容如下 一.MYSQL的安装 1.打开下载的mysql安装文件,双击运行mysql-5.5.40-win32.msi. 2.选择安装类型, ...

最新文章

  1. NASA科学家联名求撤稿:金星有生命迹象是大乌龙,12阶多项式拟合不靠谱
  2. 大咖云集!Kubernetes and Cloud Native Meetup 深圳站开始报名!
  3. RocketMQ集群知识介绍
  4. IDEA集成maven流程图详细介绍
  5. TCP握手为什么需要三次通信
  6. css3 切换贞动画的效果,仿gif效果
  7. MACOS,应用签名后就崩溃?
  8. ZOJ 1111 Poker Hands
  9. 【手写数字识别】基于matlab GUI RBM神经网络手写数字识别【含Matlab源码 1109期】
  10. JAVA经纬度距离计算并排序-Spatial4j+ForkJoin
  11. linux glibc 升级失败,glibc升级失败后的处理过程
  12. 微信小程序——事件绑定
  13. 51单片机最小系统电路图
  14. 如何高效学习和阅读源码?
  15. android 短信 易用性总结,详解短信验证和邮件验证的区别
  16. ps最大兼容 计算机一级,Photoshop最大兼容是什么意思?最大兼容使用解析
  17. GnuRadio Hacking②:使用SDR嗅探北欧芯片无线键盘鼠标数据包
  18. 有道云笔记的markdown编辑器如何通过mathtype来写公式
  19. 旋转编码器的原理和使用方法
  20. 51单片机的花卉、农田自动浇水灌溉系统开发,Proteus仿真,原理图和C代码

热门文章

  1. xbin目录及toolbox,toybox
  2. Android手机 通过NFC读取二代证信息
  3. 【力扣每日一题】691. 贴纸拼词
  4. cellspace的css做法
  5. (一)并发编程:进程与线程
  6. 主机探测命令-nmap初级操作典型用法
  7. 睡前故事-世界对你说晚安
  8. 根据年份获取所有周次及每周的开始-结束日期
  9. 前端(HTML 与 CSS)必读书籍推荐
  10. 14.ES 之 nested 详解(2019-05-22)