Spring Boot集成Keycloak如何配置支持认证/匿名访问的可选鉴权端点
问题原因
你现在卡壳的核心是两个配置语义没搞对:
- 配
keycloak.securityConstraints[0].authRoles[0] = *的时候,规则是这个路径必须是已认证用户才能进,不管什么角色都行,匿名请求直接被Keycloak过滤器拦在外面,根本到不了控制器 - 把安全约束全删了之后,Keycloak默认不会给非受保护的路径解析请求头里带的Token,就算请求带了合法的Bearer Token,控制器里拿的
Principal也会是null
实现方案
根据你用的整合方式二选一调整就行:
场景1:直接用Keycloak官方Spring Boot Starter,没写自定义Spring Security配置
- 把
application.properties里原来的安全约束配置替换成下面的:
# 配置公共路径,不强制要求认证 keycloak.securityConstraints[0].securityCollections[0].name = public keycloak.securityConstraints[0].securityCollections[0].patterns[0] = /* # 注意:这个约束不要配authRoles属性,就代表路径允许匿名访问 # 核心开关 keycloak.bearer-only = true # 用Bearer Token模式校验凭证,没带Token或者Token无效的时候不跳登录页,直接放行 keycloak.ssl-required = external keycloak.principal-attribute = preferred_username keycloak.use-resource-role-mappings = true
- 改下控制器代码,避免空指针和类型转换报错:
@RestController public class HelloController { @GetMapping("/") public String index(Principal principal) { // 先判断Principal类型,匿名访问的时候Principal要么是null要么是匿名身份对象,直接返回公共内容 if (principal instanceof KeycloakPrincipal) { KeycloakPrincipal keycloakPrincipal = (KeycloakPrincipal) principal; String username = keycloakPrincipal.getKeycloakSecurityContext().getToken().getPreferredUsername(); return "Hello " + username; } return "Hello"; } }
如果你用Java 16及以上版本,直接用
instanceof KeycloakPrincipal keycloakPrincipal的模式匹配写法省掉强转步骤就行。
场景2:自己写Spring Security配置类整合Keycloak
如果是通过继承KeycloakWebSecurityConfigurerAdapter做安全配置,直接调整HttpSecurity的访问规则就可以:
@Configuration @EnableWebSecurity public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { super.configure(http); http .csrf().disable() .authorizeRequests() // 目标路径设为permitAll,允许匿名访问,Keycloak过滤器会自动解析请求带的有效Token填充认证上下文 .antMatchers("/").permitAll() // 其他需要强制登录的路径正常配置规则就行 .anyRequest().authenticated() .and() // 开匿名身份配置,没带有效凭证的请求会被赋予匿名身份,正常进到控制器 .anonymous(); } // 剩下的Keycloak相关配置(会话策略、密钥配置之类的)保持原来的逻辑不用改 }
控制器代码和场景1的写法完全一致。
注意事项
- 别给需要支持匿名访问的路径配
authRoles=*,这个配置等价于Spring Security里的authenticated(),会把所有没认证的请求直接拦下来 - 别上来就把
Principal直接强转成KeycloakPrincipal,必须先做类型判断,不然匿名访问的时候必抛空指针或者类型转换异常 - 要是按上面配置完还是拿不到已认证用户信息,先检查是不是自己加的自定义过滤器提前清空了SecurityContext,或者把Keycloak的认证过滤器设成了只拦截受保护路径
内容的提问来源于stack exchange,提问作者Stijn
相关产品推荐
相关产品推荐

