(三)keycloak 基于SpringBoot、Servlet的客户端开发

系列目录

(一)keycloak 部署运行及源码打包
(二)keycloak 配置运行
(三)keycloak 基于SpringBoot、Servlet的客户端开发
(四)keycloak 自定义用户(SPI)开发
(五)keycloak 自定义主题
(未完成)(六)keycloak 添加登录验证码功能
(七)keycloak 设置客户端访问类型 bearer-only
(八)keycloak 设置客户端访问类型 confidential
(九)keycloak使用nginx来配置https



前言

keycloak是一套完整的开源认证授权管理解决方案,由红帽开发,提供了多种语言库,方便集成。本系列教程以使用为主,介绍keycloak的搭建,源码编译,以及部分功能的二次开发。

keycloak官网提供了详细的教程以及示例,可以参考官网示例进行编写开发。
官网地址 本系列教程基于官网最新版本18.0进行编写。

本章内容接 上一篇 (二)keycloak 配置运行 继续

keycloak提供了很多adapter来对接系统,不仅仅是针对java语言,官方文档路径

https://www.keycloak.org/docs/latest/securing_apps/#_oidc

文档中介绍了oidc和saml2.0 两种协议的adapter,我们主要一oidc协议为例介绍

注意:keycloak官方今年已经开始放弃维护大部分的adapter,主要精力要放在keycloak程序本身上。这些协议本身就有很多开源的工具包可以使用,比如pac4j之类的。

启用和保留的adapter包括以下:
在这里插入图片描述
更详细的内容,参考原文 https://www.keycloak.org/2022/02/adapter-deprecation

主要介绍基于SpringBootServlet两种adapter 以oidc协议方式接入到keycloak单点登录系统中


一.基于Springboot Adapter 接入

SpringBoot 适配器接入的方式仅适用您的SpringBoot项目以jar(内嵌容器)的方式运行,如果需要将项目打包成war,请切换成Servlet方式或者tomcat、jetty等容器的方式。

1.1 包引用

默认你已经创建了一个空白的springboot项目,打开项目maven的pom.xml文件,引入如下包:

<dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.keycloak.bom</groupId>
        <artifactId>keycloak-adapter-bom</artifactId>
        <version>18.0.0</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
 </dependencyManagement>
<dependencies>
    <!-- keycloak -->
    <dependency>
      <groupId>org.keycloak</groupId>
      <artifactId>keycloak-spring-boot-starter</artifactId>
    </dependency>
 </dependencies>

1.2 配置springboot文件

打开springboot的配置文件,如:application.yml,以yml格式配置为例

keycloak:
  auth-server-url: http://192.168.100.1:8080/  #keycloak服务的地址
  realm: test  #实例名
  resource: testA  #项目名,由服务方提供
  public-client: true
  securityConstraints:
    # 白名单页面,不设置authRoles值即可
    - authRoles:
      securityCollections:
        - name: public
          patterns:
            - /static/*
    # 使用base_user角色保护的页面
    - authRoles:
        - base_user		#角色
      securityCollections:
        - name: protected resource	#值可填任意值
          patterns:
            - /*		#项目中需要被单点登录认证的请求,根据项目实际情况配置
  ssl-required: external

1.3 编写测试Controller

我们写一个测试Controller,模拟首页和非保护页面

@RestController
public class IndexController {

    /**
     * 不受保护的页面
     * @param request
     * @return
     */
    @RequestMapping("/static")
    public String static() {
        return "不受保护的页面";
    }

    /**
     * 模拟首页
     * @param request
     * @return
     */
    @RequestMapping("/")
    public String index(HttpServletRequest request) {
        return "首页";
    }
}

1.4 运行测试

现在启动springboot项目,我们以main方法的方式运行,然后打开浏览器,分别输入

  • http://127.0.0.1:8080/demo/static (不受保护)
  • http://127.0.0.1:8080/demo/ (受到保护)

如果配置正确的话, 不受保护 的页面能够正常打开
打开受到保护的页面,系统将自动跳转到keycloak的登录页面,输入用户名密码后,将自动从定向到我们模拟的首页

1.5 获取登录用户

当我们能够通过keycloak正确登录系统后,我们一般都需要获取到当前登录用户的用户信息,获取用户信息也非常简单
我们在刚才模拟的首页中获取下用户的基本信息

/**
     * 模拟首页
     * @param request
     * @return
     */
    @RequestMapping("/")
    public String index(HttpServletRequest request) {

        //从session中获取到keycloak上下文对象 springboot 方式
        RefreshableKeycloakSecurityContext session = (RefreshableKeycloakSecurityContext)request.getAttribute(KeycloakSecurityContext.class.getName());

        if(null == session)
            return "未登录....";

        //从上下文对象中获取到token
        AccessToken token = session.getToken();
 
        //用户的基本信息
        final String result = String.format(
                        "<html>" +
                        "<h2>%s</h2>" +
                        "<li>userid:%s</li>" +
                        "<li>name: %s</li>" +
                        "<li>email: %s</li>" +
                        "<li>prename: %s</li>" +
                        "<li>givename: %s</li>" +
                        "<li>familyName: %s</li>" +
                        "<li>phone: %s</li>" +
                        "<li>nickname: %s</li>" +
                        "<li>%s</li>",
                token.getIssuedFor(),
                token.getSubject(),
                token.getName(),
                token.getEmail(),
                token.getPreferredUsername(),
                token.getGivenName(),
                token.getFamilyName(),
                token.getPhoneNumber(),
                token.getNickName(),
                "<a href='/demo/logout'>退出</a>");

        return result;
    }

1.6 退出

当系统登录成功后,我们需要实现退出功能,如何实现全局的退出呢?
回到刚才测试的Controller中,我们添加一个logout方法,在logout中使用 request.logout() 即可实现退出功能。

/**
     * 退出
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    @GetMapping("/logout")
    public void logout(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.logout();
        //跳转到首页(或其他需要验证的页面),进行登录验证,单点登录会自动跳转到登录页
        response.sendRedirect("/demo");
    }

退出非常简单,当然你可以在前端页面直接调用系统的退出请求进行退出,而不用写自己的退出请求。退出请求的url地址格式:

http://auth-server/realms/{realm-name}/protocol/openid-connect/logout

请求需要传递两个参数,不然会出现一个确认退出的界面

  • id_token_hint 值内容:session.getIdTokenString()
  • post_logout_redirect_uri 退出成功后跳转的页面

二.基于Servlet Adapter的方式接入

用Servlet的方式可以将项目打包成war包放在tomcat等其他容器中运行,配置比springboot稍微多几步,也非常简单。我们基于刚才的空白SpringBoot项目进行编码

2.1 包引用

打开pom文件,在pom文件中添加

<!-- servlet 方式 -->
<dependency>
  <groupId>org.keycloak</groupId>
  <artifactId>keycloak-servlet-filter-adapter</artifactId>
  <version>18.0.1</version>
</dependency>

2.2 配置

首先,在项目中创建一个webapp目录,然后再webapp目录下添加WEB-INF文件夹,在WEB-INF下田间一个keycloak.json文件。目录结构如下:
在这里插入图片描述

keycloak.json的内容如下:

 {
  "realm": "test",
  "auth-server-url": "http://127.0.0.1:8080/",
  "ssl-required": "external",
  "resource": "testA",
  "public-client": true,
  "confidential-port": 0
}

文件内容也可以在控制台的,客户端->安装 中找到
在这里插入图片描述

2.3 添加Servlet Adapter 的 Filter

添加servlet 拦截器,用来拦截请求,添加拦截器有多种方式,你可以直接在web.xml中直接添加。我们的测试示例使用了SpringBoot项目,可以直接利用SpringBoot来创建一个 FilterRegistrationBean 对象代理filter。
创建一个 DemoKeycloakConfig.java

/**
 * @autor ChangSir
 * @description keycloak servlet的配置
 * @date 2022/6/23 18:07
 */
@Configuration
public class DemoKeycloakConfig {

    private Logger log = LoggerFactory.getLogger(DemoKeycloakConfig.class);

    /**
     * 注册servelt filter的方法
     * @return
     */
    @Bean
    public FilterRegistrationBean<KeycloakOIDCFilter> KeycloakOIDCFilterBean() {
        log.info("注册Servelt filter");
        FilterRegistrationBean<KeycloakOIDCFilter> filterRegistrationBean = new FilterRegistrationBean<>();
        filterRegistrationBean.setFilter(new KeycloakOIDCFilter());
        //白名单路径
        filterRegistrationBean.addInitParameter("keycloak.config.skipPattern", "/static/*");
        //需要被拦截的路径
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.setOrder(0);
        return filterRegistrationBean;
    }
}

如果你需要修改keycloal.json文件的路径,也可以在创建FilterRegistrationBean中进行配置,示例如下:

 @Bean
 public FilterRegistrationBean<KeycloakOIDCFilter> KeycloakOIDCFilterBean() {
     .....
     // 对应项目中的webapp文件夹, 默认配置文件为 /WEB-INF/keycloak.json
     // 如果您需要重名名或修改路径,可以单独在此设置
    filterRegistrationBean.addInitParameter("keycloak.config.path", "/WEB-INF/keycloak.json");
     .....
 }

如果你使用了idea开发,并且用main函数的方式运行了springboot项目,有可能会无法读取到webapp目录下的文件,此时可以在idea的设置里面配置运行参数即可
在这里插入图片描述
添加 Working directory 参数为 $ MODULE_WORKING_DIR $
在这里插入图片描述

2.4 运行测试

Servlet方式的运行,获取用户信息,以及退出和第一种Springboot Adapter方式一样,不再重复描述

2.5 注意事项

Servlet方式的运行,需要注意,在默认配置下无法实现用户角色的校验,需要我们自己手动实现用户角色校验功能,解决思路:

利用 httpServletRequest的 isUserInRole 方法来判断用户是不是具备某个角色
比如:request.isUserInRole(“base_url”);

这个判断,你可以单独写个Spring的拦截器来处理,我们这里不做详细介绍,需要参考示例的,可以在评论区回复我

2.6 全部退出问题

使用servlet或者springboot接入keycloak,当你有多个系统同时接入时,可能会出现,退出其中一个系统后,其他系统没有退出的情况。这里可以利用 客户端的配置页面中的 管理员员网址 一项来解决
在这里插入图片描述

在此栏中填写你项目的地址加上/k_logout,或其你自己的退出地址即可。
官方文档中针对此处的说法:

The Admin URL will make callbacks to the Admin URL to do things like
backchannel logout. So, the Admin URL in this example should be
http://hostname/{context-root}/keycloak.

总结

下一章节我们将实现我们自定义的用户,将我们现有系统的用户接入到keycloak中

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ChangSir-86

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值