Keycloak为流行的Java应用程序提供适配器。在本系列的上一篇文章中,我们通过一种适配器演示了SpringBoot的安全保护。Keycloak还提供了SpringSecurity适配器。在接下来的几篇文章中,我们将一起学习如何使用SpringSecurity适配器。Keycloak的安装可以参考之前的系列教程。适配器集成在Spring应用中,我们集成了keycloak-spring-security-adapter:org.keycloakkeycloak-spring-security-adapter15.0.0可以这样集成到SpringBoot中:org.springframework.bootspring-boot-starter-securityorg.keycloakkeycloak-spring-boot-starter15.0.0然后就可以使用SpringSecurity的特性了集成Keycloak。Keycloak提供了一个KeycloakWebSecurityConfigurerAdapter作为创建WebSecurityConfigurer实例的方便的基类。我们可以写一个配置类来自定义我们的安全策略,像这样:@KeycloakConfigurationpublicclassSecurityConfigextendsKeycloakWebSecurityConfigurerAdapter{/***注册了一个KeycloakAuthenticationProvider*/@AutowiredpublicvoidconfigureGlobal(AuthenticationManagerBuilderauth)throwsException{auth.authentication;Provider)Akvider(/***Definesessionstrategy*/@Bean@OverrideprotectedSessionAuthenticationStrategysessionAuthenticationStrategy(){returnnewRegisterSessionAuthenticationStrategy(newSessionRegistryImpl());}/***常用的SpringSecurity安全策略*/@Overrideprotectedvoidconfigure(HttpSecurityhttp)throws.httpconfig({super.authorizeRequests().antMatchers("/customers*").hasRole("USER").antMatchers("/admin/**").hasRole("base_user").anyRequest().permitAll();}}注意:以上配置不成功,配置完以上然后我们直接启动应用,结果并不如预期:java.io.FileNotFoundException:UnabletolocateKeycloakconfigurationfile:keycloak.json抛出找不到keycloak.json文件的异常。Keycloak支持的每个Java适配器都可以通过一个简单的JSON文件进行配置,而我们缺少的就是这个文件。{"realm":"demo","re??source":"customer-portal","re??alm-public-key":"MIGfMA0GCSqGSIb3D...31LwIDAQAB","auth-server-url":"https://localhost:8443/auth","ssl-required":"external","use-resource-role-mappings":false,"enable-cors":true,"cors-max-age":1000,"cors-allowed-方法”:“POST,PUT,DELETE,GET”,“cors-exposed-headers”:“WWW-Authenticate,My-custom-exposed-Header”,“bearer-only”:false,“enable-basic-auth”:false,"expose-token":true,"verify-token-audience":true,"credentials":{"secret":"234234-234234-234234"},"connection-pool-size":20,"socket-timeout-millis":5000,"connection-timeout-millis":6000,"connection-ttl-millis":500,"disable-trust-manager":false,"allow-any-hostname":false,"truststore":"path/to/truststore.jks","truststore-password":"geheim","client-keystore":"path/to/client-keystore.jks","client-keystore-password":"geheim","client-key-password":"geheim","token-minimum-time-to-live":10,"min-time-between-jwks-requests":10,"public-key-cache-ttl":86400,"redirect-rewrite-rules":{"^/wsmaster/api/(.*)$":"/api/$1"}}上面包含的客户端配置属性都可用在Keycloak控制台进行配置,如下图所示:配置Keycloak客户端属性就是说我们需要的json文件对应图中的配置项,更人性化的是我们不需要自己写这个json文件.keycloak提供了下载客户端配置的方法,这里我只使用必要的配置项:可以下载客户端json配置,导入客户端配置,虽然可以成功获取到json文件,但是加载json并不顺利配置后我的探索,需要实现一个KeycloakConfigResolver并注入SpringIoC,有以下两种实现方式。复用SpringBootAdapter配置,直接复用SpringBoot的配置形式,首先声明SpringBoot的KeycloakConfigResolver实现:repeatUsetheconfigurationofSpringBoot'sapplication.yaml:重新使用SpringBoot配置项原有的角色资源映射约束失效。对于自定义实现,也可以自定义编写和解析。这个时候json形式就不重要了。你可以把json文件的内容存放在任何你擅长的地方。/***自己写解析**@returnthekeycloakconfigresolver*/@BeanpublicKeycloakConfigResolverfileKeycloakConfigResolver(){returnnewKeycloakConfigResolver(){@SneakyThrows@OverridepublicKeycloakDeploymentresolve(HttpFacade.Requestrequest){//json文件放到resources文件夹类".下ClassPathResource=newClassPathResource.json");AdapterConfigadapterConfig=newObjectMapper().readValue(classPathResource.getFile(),AdapterConfig.class);returnKeycloakDeploymentBuilder.build(adapterConfig);}};}角色命名策略SpringSecurity会给每个角色加上ROLE_前缀,这个需要我们通过声明GrantedAuthoritiesMapperSimpleAuthorityMapper的实现来完成这个功能。keycloak在KeycloakAuthenticationProvider中配置了这个函数:KeycloakAuthenticationProviderauthenticationProvider=keycloakAuthenticationProvider();authenticationProvider.setGrantedAuthoritiesMapper(newSimpleAuthorityMapper());完成配置applicaiton.yaml:keycloak:#声明客户端所在realmrealm:felord.cn#keycloak-server-url:http://localhost:8011/auth#Clientnameresource:springboot-client#声明这是publicclient,否则不能在keycloak的外部环境使用,这里会是403public-client:true结合Keycloak导出的json文件配置。SpringSecurity配置:@KeycloakConfigurationpublicclassSecurityConfigextendsKeycloakWebSecurityConfigurerAdapter{/***复用springboot的方法**@returnthekeycloakconfigresolver*/@BeanpublicKeycloakConfigResolverkeycloakConfigResolver(){returnnewKeycloakSpringBootConfigResolver();}/***自己写解析**@returnthekeycloakconfigresolver*///@BeanpublicKeycloakConfigResolverfileKeycloakConfigResolver(){returnrequest->{//json文件放在resources文件夹下.class);}catch(IOExceptione){e.printStackTrace();}returnKeycloakDeploymentBuilder.build(adapterConfig);};}/***Configuration{@linkAuthenticationManager}*这里会介绍Keycloak的{@linkAuthenticationProvider}实现**@paramauththeauth*/@AutowiredpublicvoidconfigureGlobal(AuthenticationManagerBuilderauth){KeycloakAuthenticationProviderauthenticationProvider=钥匙斗篷AuthenticationProvider();authenticationProvider.setGrantedAuthoritiesMapper(newSimpleAuthorityMapper());auth.authenticationProvider(authenticationProvider);}/***会话身份验证策略*/@Bean@OverrideprotectedSessionAuthenticationStrategysessionAuthenticationStrategy(){returnnewRegisterSessionAuthenticationStrategy(newSessionRegistry)};/***I配置session监听器保证单点退出生效**@returntheservletlistenerregistrationbean*/@BeanpublicServletListenerRegistrationBeanhttpSessionEventPublisher(){returnnewServletListenerRegistrationBean<>(newHttpSessionEventPublisher());}@Overrideprotectedvoidconfigure(HttpSecurityhttp)throwsException{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只能获取正确的用户密码Expected结果典型的授权代码流程。总结一下Keycloak集成SpringSecurity的要点。这里需要再次梳理一下。在原生情况下,Keycloak负责客户端配置、用户信息和角色信息;客户端只负责角色与资源的映射关系。后续会深入定制Keycloak和SpringSecurity来满足实际场景的需求。本文转载自微信公众号“码农小胖哥”,可通过以下二维码关注。转载本文请联系码农小胖公众号。