Keycloak对流行的Java应用提供了适配器。在系列文章的上一篇我们演示了针对Spring Boot的安全保护,用的就是适配器的一种。Keycloak同样提供Spring Security的适配器,后续的几篇文章我们就来共同学习Spring Security适配器的使用。
Keycloak的安装可参考前面的系列教程。
适配器集成
在Spring 应用中我们集成keycloak-spring-security-adapter:
-
org.keycloak -
keycloak-spring-security-adapter -
15.0.0 -
在Spring Boot中可以这样集成:
-
org.springframework.boot -
spring-boot-starter-security -
-
org.keycloak -
keycloak-spring-boot-starter -
15.0.0 -
然后就能利用Spring Security的特性来集成Keycloak。Keycloak 提供了一个 KeycloakWebSecurityConfigurerAdapter 作为创建WebSecurityConfigurer 实例的方便基类。我们可以编写了一个配置类来定制我们的安全策略,就像这样:
- @KeycloakConfiguration
- public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter
- {
-
- @Autowired
- public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
- auth.authenticationProvider(keycloakAuthenticationProvider());
- }
-
-
- @Bean
- @Override
- protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
- return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
- }
-
-
- @Override
- protected void configure(HttpSecurity http) throws Exception
- {
- super.configure(http);
- http
- .authorizeRequests()
- .antMatchers("/customers*").hasRole("USER")
- .antMatchers("/admin
- @Bean
- public KeycloakConfigResolver keycloakConfigResolver() {
- return new KeycloakSpringBootConfigResolver();
- }
然后复用Spring Boot的application.yaml的配置项:
复用Spring Boot配置项
原来的角色资源映射约束失效。
自定义实现
你也可以自定义写解析,这个时候json形式已经不重要了,你可以将json文件的内容存储到任何你擅长的地方。
-
- @Bean
- public KeycloakConfigResolver fileKeycloakConfigResolver() {
- return new KeycloakConfigResolver() {
- @SneakyThrows
- @Override
- public KeycloakDeployment resolve(HttpFacade.Request request) {
- // json 文件放到resources 文件夹下
- ClassPathResource classPathResource = new ClassPathResource("./keycloak.json");
- AdapterConfig adapterConfig = new ObjectMapper().readValue(classPathResource.getFile(), AdapterConfig.class);
-
- return KeycloakDeploymentBuilder.build(adapterConfig);
- }
- };
- }
角色命名策略
Spring Security会为每个角色添加ROLE_前缀,这需要我们声明GrantedAuthoritiesMapper的实现SimpleAuthorityMapper来完成这一功能。Keycloak在KeycloakAuthenticationProvider中配置该功能:
- KeycloakAuthenticationProvider authenticationProvider = keycloakAuthenticationProvider();
- authenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
完整的配置
applicaiton.yaml:
- keycloak:
- # 声明客户端所在的realm
- realm: felord.cn
- # keycloak授权服务器的地址
- auth-server-url: http://localhost:8011/auth
- # 客户端名称
- resource: springboot-client
- # 声明这是一个公开的客户端,否则不能在keycloak外部环境使用,会403
- public-client: true
这里要结合Keycloak导出的json文件配置。
Spring Security配置:
- @KeycloakConfiguration
- public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
-
-
- @Bean
- public KeycloakConfigResolver keycloakConfigResolver() {
- return new KeycloakSpringBootConfigResolver();
- }
-
- // @Bean
- public KeycloakConfigResolver fileKeycloakConfigResolver() {
- return request -> {
- // json 文件放到resources 文件夹下
- ClassPathResource classPathResource = new ClassPathResource("./keycloak.json");
- AdapterConfig adapterConfig = null;
- try {
- adapterConfig = new ObjectMapper().readValue(classPathResource.getFile(),
- AdapterConfig.class);
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- return KeycloakDeploymentBuilder.build(adapterConfig);
- };
- }
-
- @Autowired
- public void configureGlobal(AuthenticationManagerBuilder auth) {
- KeycloakAuthenticationProvider authenticationProvider = keycloakAuthenticationProvider();
- authenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
- auth.authenticationProvider(authenticationProvider);
- }
-
- @Bean
- @Override
- protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
- return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
- }
-
- @Bean
- public ServletListenerRegistrationBean
httpSessionEventPublisher() { - return new ServletListenerRegistrationBean<>(new HttpSessionEventPublisher());
- }
- @Override
- protected void configure(HttpSecurity http) throws Exception {
- super.configure(http);
- http
- .authorizeRequests()
- .antMatchers("/customers*").hasRole("USER")
- .antMatchers("/admin/**").hasRole("base_user")
- .anyRequest().permitAll();
- }
- }
调用流程
资源客户端springboot-client有一个接口/admin/foo,当未登录调用该接口时会转发到:
- http://localhost:8011/auth/realms/felord.cn/protocol/openid-connect/auth?response_type=code&client_id=springboot-client&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fsso%2Flogin&state=ec00d608-5ce7-47a0-acc8-8a20a2bfadfd&login=true&scope=openid
输入正确的用户密码后才能得到期望的结果。
典型的authorazation code flow。
总结
Keycloak整合Spring Security的要点这里需要再梳理一下。在原生情况下,客户端的配置、用户的信息、角色信息都由Keycloak负责;客户端只负责角色和资源的映射关系。后续会深入并定制Keycloak和Spring Security以满足实际场景需要。
本文转载自微信公众号「码农小胖哥」,可以通过以下二维码关注。转载本文请联系码农小胖哥公众号。