第一步:在keycloak平台上,新建一个client app

联系Keycloak管理员,提供 应用的 root url 和 app name即可。

建好client之后,可以得到一个 client secret(密匙)。

第二步:在client project中 加入 keycloak配置

配置形如:

# 空间名,默认所有app和用户都在一个keycloak空间

keycloak.realm=ops

# keycloak服务器的auth地址

keycloak.auth-server-url=http://localhost:8180/auth

# client app name

keycloak.resource=fm-cache-cloud

# client secret

keycloak.credentials.secret=d4589683-0ce7-4982-bcd3-c48a12572f79

# 登录url和所需要的role

keycloak.securityConstraints[0].authRoles[0] = user

keycloak.securityConstraints[0].securityCollections[0].patterns[0] = /manage/ssologin/*

上面的配置,除了 最后一项,其他都是基本配置,直接填好就行了。

最后一项需要先在controller中定义这样一个用于登录的url,下面会讲。

在讲第三步之前,说一下Keycloak客户端接入原理:

(keycloak支持很多种方式接入,我只讲其中一部分)

基本原理

keycloak是JBOSS开源的,JBOSS是做服务器的,所以,对于服务器,它比谁都玩得熟,Keycloak的强大之处也在于,它对于客户端应用的管控,直接可以到 服务器层面(相当于给服务器装一个插件,然后进入这个服务器的请求,都会被拦截和认证)。

本文以我们常用的Spring Boot 内嵌的 Tomcat 服务器 为例,在项目中引入 keycloak包并配置好之后,实际上开启了一个 tomcat的 filter,这个filter会拦截指定的url,如果没登录,就跳转到统一登录页面进行登录。

(如果不是用的Spring boot内嵌的tomcat服务器,比如用的是独立的tomcat服务器,原理也是一样的,只是配置方法不一样)

keycloak提供了很多种插件(adapter),例如仅Java的adapter就有如下:

2.1.1. Java Adapter Config

2.1.2. JBoss EAP/WildFly Adapter

2.1.4. JBoss Fuse 6、7 Adapter

2.1.6. Spring Boot Adapter

2.1.7. Tomcat 6, 7 and 8 Adapters

2.1.8. Jetty 9.x Adapters

2.1.9. Jetty 8.1.x Adapter

2.1.10. Spring Security Adapter

2.1.11. Java Servlet Filter Adapter

下面以 Spring Boot Adapter为例,说明如何装插件。其他服务器,或者其他语言的客户端是类似的,很简单。

安装方法:

例如 spring boot 1.x,在pom.xml中引入下面依赖即可:

<!-- Keycloak  -->

<dependency>

    <groupId>org.keycloak</groupId>

    <artifactId>keycloak-legacy-spring-boot-starter</artifactId>

    <version>5.0.0</version>

</dependency>

如果是spring boot 2.x版本,上面的 starter 换成 keycloak-spring-boot-starter。

由于keycloak是基于 filter拦截器的,所以如果 项目本身 已经用了filter来作为登录控制的话,则需要进行改造,Java项目常见情况如下:

1、基于shiro框架进行登录控制;

2、基于spring security进行登录控制;

3、基于自定义简单的servlet filter进行登录控制;

下面,针对 2、3 项目情况,说明如何进行集成配置(注意,不同的项目,情况可能不完全一样,只要掌握思路即可)。

第三步(针对“3、基于简单servlet filter登录的项目”)

改造之前:

  • 原项目,采用了filter来拦截请求,如果没登录,则跳转到登录页面(比如 /mange/login)。

  • 使用项目自带的登录页面,进行登录。

改造之后:

  • 沿用原来的filter,但是如果没登录,则跳转到 用于统一登录的指定controller(比如 /mange/ssologin);

  • 把这个统一登录的controller的url,配置成 keycloak拦截的登录地址,使用keycloak来进行登录;

这个controller,逻辑很简单,一个例子如下,流程见注释:

@GetMapping("/ssologin")

public View ssologin(HttpServletRequest request) {

    // 1、从request获取用户名,再查看本系统中有无此用户

    // 2、有这个用户,则执行登录成功逻辑,代表登录成功

    // 3、没有这个用户,则执行登录失败逻辑,比如跳转到登录页面

}

一个真实例子:

@RequestMapping(value = "/ssologin", method = RequestMethod.GET)

public ModelAndView ssologin(HttpServletRequest request, HttpServletResponse response) {

    // 从request获取用户名,再查看本系统中有无此用户

    String userName = Identity(request).getName();

    AppUser user = userService.getByName(userName);

    if (user == null) {

        return new ModelAndView("redirect:/manage/login");

    else {

        // 有这个用户,则添加到session或者cookie中,代表登录成功

        userLoginService.addLoginStatus(request, response, user.getId().toString());

    }

    // 返回用户主页

    return new ModelAndView("redirect:/admin/app/list.do");

}

登录原理 说明:

由于在keycloak配置中加入了url权限控制,如下

# 登录url和所需要的role

keycloak...authRoles[0] = user

keycloak...patterns[0] = /manage/ssologin/*

那么,访问这个 url,在没登录的情况下,就会跳转到 统一登录页面,用户输入用户密码成功登录之后,就会进入到上面定义的 controller中,再执行应用本地的登录逻辑即可。

退出登录,很简单,只需要执行  HttpServletRequest.logout() 即可

例如:

@GetMapping(value = "/logout")

public void logout(HttpServletRequest request) throws ServletException {

    // 先移除本地的session或者cookie

    userLoginService.removeLoginStatus(request, response);

    // 然后执行 request.logout() 即可

    request.logout();

}

第三步(针对“2、基于spring security进行登录的项目”)

改造之前:

  • 请求被spring security的UsernamePasswordAuthenticationFilter拦截,判断是否登录,如果未登录,则跳转到项目自己的登录页面。

  • 使用项目自带的登录页面,进行登录。

准备工作:写一个KeycloakAuthenticationFilter,重载spring security的UsernamePasswordAuthenticationFilter,它的逻辑是,先判断有没有用户进行统一登录,如果用户已经统一登录了,但是本地没登录,则进行本地登录。

改造之后:

  • 请求被spring security的KeycloakAuthenticationFilter拦截,判断是否登录,如果未登录,则跳转到 用于统一登录的指定controller(比如 /keycloak/ssologin);

  • 把这个统一登录的controller的url,配置成 keycloak拦截的登录地址,使用keycloak来进行登录;

  • keycloak登录的controller执行成功之后,再跳转到spring security的登录处理url进行登录。

改造之前,spring security配置如下

  @Override

  protected void configure(HttpSecurity http) throws Exception {

    http.csrf().disable();

    http.headers().frameOptions().disable();

    http.authorizeRequests().antMatchers("/openapi/**""/keycloak/**""/img/**")

    .permitAll().antMatchers("/**").hasAnyRole(USER_ROLE);

    http.formLogin().loginPage("/signin").permitAll().loginProcessingUrl("/sslogin")

        .failureUrl("/signin?#/error").and().httpBasic();

    http.logout().invalidateHttpSession(true).clearAuthentication(true)

        .logoutSuccessUrl("/signin?#/logout");

    http.exceptionHandling().authenticationEntryPoint(

        new LoginUrlAuthenticationEntryPoint("/signin?#/logout"));

  }

改造之后,spring security配置如下:

  @Override

  protected void configure(HttpSecurity http) throws Exception {

    http.csrf().disable();

    http.headers().frameOptions().disable();

    http.authorizeRequests().antMatchers("/openapi/**""/keycloak/**""/img/**")

    .permitAll().antMatchers("/**").hasAnyRole(USER_ROLE);

    http.formLogin().loginPage("/signin").permitAll().loginProcessingUrl("/sslogin")

        .failureUrl("/signin?#/error").and().httpBasic().and()

        // add by zollty

        .addFilterBefore(keycloakAuthenticationFilter(), BasicAuthenticationFilter.class);

    http.logout().invalidateHttpSession(true).clearAuthentication(true)

        .logoutSuccessUrl("/signin?#/logout")

        // add by zollty

        .addLogoutHandler(new KeycloakSpringLogoutHandler());

    http.exceptionHandling().authenticationEntryPoint(

        // to keycloak ssologin controller

        new LoginUrlAuthenticationEntryPoint("/keycloak/ssologin"));

  }

即,加了一个自定义的 keycloakAuthenticationFilter 和 KeycloakSpringLogoutHandler,同时 将LoginUrlAuthenticationEntryPoint登录地址,修改成 用于统一登录的指定controller的URL。这个controller代码如下:

@RequestMapping(value = "keycloak/ssologin", method = RequestMethod.GET)

public ModelAndView ssologin() {

    return new ModelAndView("redirect:/sslogin");

}

进入到这个方法,代表已经sso登录成功,然后直接跳转到 spring security的loginProcessingUrl进行本地登录即可。

KeycloakSpringLogoutHandler的代码如下:

public class KeycloakSpringLogoutHandler implements LogoutHandler {

    @Override

    public void logout(HttpServletRequest request, HttpServletResponse response

                        , Authentication authentication) {

        

        // 退出keycloak sso

        try {

            request.logout();

        catch (ServletException e) {

            e.printStackTrace();

        }

        

    }

}

其作用是退出统一登录。

KeycloakAuthenticationFilter的代码如下:

public class KeycloakAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    

    static final String DEFAULT_PASSWD_SIGN = "`kc`";

    @Override

    public Authentication attemptAuthentication(HttpServletRequest request, 

            HttpServletResponse response) throws AuthenticationException {

     

        String username = obtainUsername(request);

        String password = null;

        

        Identity identity = new Identity(request);

        if (username == null && identity.getSecurityContext() != null) {

            username = identity.getName();

            password = DEFAULT_PASSWD_SIGN;

        else {

            password = obtainPassword(request);

            if (password == null) {

                password = "";

            else if(DEFAULT_PASSWD_SIGN.equals(password)) {

                throw new AuthenticationServiceException("Auth error");

            }

        }

        

        username = username.trim();

        UsernamePasswordAuthenticationToken authRequest = 

            new UsernamePasswordAuthenticationToken(username, password);

        setDetails(request, authRequest);

        return this.getAuthenticationManager().authenticate(authRequest);

    }

}

这个代码来源于spring security的UsernamePasswordAuthenticationFilter,只是加了7行代码,用于先判断是否有用户已经统一登录过,如果已经统一登录了,则将其密码设为一个特殊字符,这是一个取巧的做法,因为用户已经统一登录了,所以后面只要看到是这个特殊字符,就不再验证密码,直接登录。

其他编程语言应用的接入

方法一:自己根据OpenID Connect和OAuth2.0的原理,找到相应的client,引入自己的项目使用。

官方指导文档:https://www.keycloak.org/docs/latest/securing_apps/index.html#other-openid-connect-libraries

方法二:直接在网上或GitHub上搜索现成的第三方Client、Adapter或Demo,参照配置。例如:

1)Keycloak Golang相关的第三方adapter:

https://github.com/mitch-strong/KeycloakGo

https://github.com/cwocwo/keycloak-adapter-go

更多参见:https://github.com/search?l=Go&q=Keycloak&type=Repositories

2)Python相关的Client、Adapter或Demo:(包括Django、Flask相关的例子都有)

https://github.com/search?l=Python&q=Keycloak&type=Repositories

全文总结

在有keycloak adapter的加持下,keycloak的接入相当简单,它是可以做到不改一行代码的 —— 之所以上面提到一些小的改动,完全是 为了 替换或者 适配 原来项目已有 的登录filter配置,把原来的账号+密码的登录形式,拦截并跳转到 keycloak统一登录,登录完成之后,再在本地项目进行登录。

明白这个原理之后,其他类型的项目都是一样的处理逻辑。

具体接入时,参见这个文档 securing apps guide,说得很清楚。

另外,参考其GitHub上的 Quick-Start Demo。

附 Keycloak官网: www.keycloak.org

Special专题:关于现代化前端、移动端的接入说明

参见这篇文章:Keycloak现代化前端、移动端的接入说明。

Keycloak使用说明(Java Spring Boot)相关推荐

  1. 【直播回顾】云栖社区特邀专家徐雷Java Spring Boot开发实战系列课程(第19讲):Java Spring Cloud微服务架构模式与开发实战...

    主讲人:徐雷(云栖社区特邀Java专家) 徐雷,花名:徐雷frank:资深架构师,MongoDB中文社区联席主席,吉林大学计算机学士,上海交通大学硕士.从事了 10年+开发工作,专注于分布式架构,Ja ...

  2. Java Spring Boot VS .NetCore (七) 配置文件

    Java Spring Boot VS .NetCore (一)来一个简单的 Hello World Java Spring Boot VS .NetCore (二)实现一个过滤器Filter Jav ...

  3. Java Spring Boot 2.0 实战之制作Docker镜像并推送到Docker Hub和阿里云仓库

    内容摘要:大规模集群快速部署Java应用,需要制作Docker镜像,本次课程详细介绍如何制作Java程序的Docker镜像文件,深入解析DockerFile核心参数,以及实践演练把我们制作的Docke ...

  4. 云栖社区特邀专家徐雷——Java Spring Boot开发实战系列课程【往期直播回顾】...

    徐雷,花名:徐雷frank:资深架构师,MongoDB中文社区联席主席,吉林大学计算机学士,上海交通大学硕士.从事了 10年+开发工作,专注于分布式架构,Java Spring Boot.Spring ...

  5. 毕设项目——智慧小区系统(Java Spring Boot+Vue ElementUI)

    毕设项目--智慧小区系统(Java Spring Boot+Vue ElementUI) 项目初衷(最真实版) 系统技术分析 前端界面 后端及数据库 系统功能介绍 小区业主端 物业人员端 系统界面展示 ...

  6. Java+Spring Boot 二手书交易系统

    目录 1 系统简介 2 系统相关技术 2.1 Java EE 2.2 Springboot框架 2.3 Maven技术 2.4 Tomcat服务器 2.5 MySQL 3 需求分析 3.1 需求概述 ...

  7. Java Spring Boot 2.0实战Docker容器与架构原理,视频与课件,基于Linux环境...

    Java Spring Boot 2.0实战Docker容器Linux与架构原理 内容摘要:Docker是最流行的开源容器引擎,Go语言开发,在互联网大规模集群.云计算.微服务等架构中广泛使用.本次课 ...

  8. Java spring boot 阿里云调用人脸识别接口,本地sdk上传到阿里云调用api

    Java spring boot 阿里云调用人脸识别接口 没有写测试类,工具类如下,有access_key_id和access_key_secret传参调用就可使用 代码如下: pom.xml依赖 & ...

  9. JAVA Spring Boot与海康威视摄像头的故事

    <菜鸟学JAVA第一篇> 前言:JAVA Spring Boot与海康威视摄像头的故事 关于本贴 干货部分 进入官网,选择sdk下载: 下载所需要的开发包(以下教程以windows为例): ...

最新文章

  1. HTML中收藏和删除的小图案,YS - 《网页制作》复习题(多选题)
  2. 关于jetty的那些奇葩问题
  3. 【错误记录】Visual Studio 编译 C++ 代码报错 ( To disable deprecation, use _CRT_SECURE_NO_WARNINGS. )
  4. 【Flutter】Flutter 混合开发 ( 简介 | Flutter 混合开发集成步骤 | 创建 Flutter Module )
  5. Design Patterns(二十一):State Pattern--VB代码
  6. 货车交强险在网上能买吗?
  7. php常用字符串函数有哪些,ThinkPHP字符串函数及常用函数汇总
  8. Redis 五大数据类型的基本命令使用
  9. 华泰证券 python 自动交易软件_机智股票自动交易软件
  10. 怎么把flac转换成ogg格式
  11. Autodesk Inventor探索——齿轮参数化建模
  12. 设置http代理解决qq音乐pc版无法播放问题
  13. 树莓派和电脑之间串口通信
  14. PowerDesigner破解版下载及安装教程
  15. Python学习总结(10) python中数据的常用操作之切片和迭代
  16. 关于重装Win10系统卡死在PIN码设置步骤
  17. Zemax学习笔记(12)- 扫描系统实例
  18. ajax提交到action乱码问题
  19. P1.Pytorch环境的配置及安装(Configuration and installation of Pytorch)
  20. 成都python工作-成都Python学习哪家好 毕业可从事哪些工作

热门文章

  1. 机器学习【西瓜书/南瓜书】--- 第四章决策树
  2. Maya游戏角色骨骼绑定学习教程
  3. 申通快递机器人上岗_申通快递机器人上岗 物流机器人在中国会是个大生意
  4. html js使用svg图标,Vue项目中使用svg图标
  5. Mac应用和命令推荐
  6. 题解 | #N阶楼梯上楼问题#
  7. 架构设计说明书究竟应该包含什么
  8. 百面机器学习(5)非监督学习
  9. mysql——索引的简单介绍
  10. 网络游戏需要多大的带宽,延迟又是怎么回事