配置Keycloak Spring Boot Adapter:/api用Bearer Only,/login重定向登录
解决Keycloak Spring Boot Adapter接口认证模式区分问题
核心思路
先关闭全局的bearer-only模式,再通过Spring Security细粒度配置不同路径的认证规则:
/api/**路径强制使用Bearer Token认证(即Bearer Only,未认证返回401)- 其他路径支持重定向到Keycloak OIDC登录页面
步骤1:修改Keycloak全局配置
在application.yml(或application.properties)中,将全局bearer-only设为false——这是实现重定向登录的前提,全局设为true会强制所有接口仅接受Bearer Token,无法触发重定向流程。
示例application.yml配置:
keycloak: auth-server-url: http://你的Keycloak地址/auth realm: 你的Realm名称 resource: 你的客户端ID credentials: secret: 你的客户端密钥(仅当客户端为confidential类型时需要) bearer-only: false use-resource-role-mappings: true
步骤2:配置Spring Security规则
根据你使用的Spring Security版本,选择对应的配置方式:
方式一:使用最新的SecurityFilterChain(推荐)
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.web.SecurityFilterChain; import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationEntryPoint; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter; @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http // 配置路径权限规则 .authorizeHttpRequests(auth -> auth .requestMatchers("/login").permitAll() // 允许匿名访问/login路径 .requestMatchers("/api/**").authenticated() // /api/**路径必须认证 .anyRequest().authenticated() // 其他路径也需认证(可按需调整) ) // 配置OIDC登录流程,自动重定向到Keycloak登录页 .oauth2Login() // 配置资源服务器,对/api/**使用Bearer Token认证 .oauth2ResourceServer(oauth2 -> oauth2 .jwt(jwt -> jwt .jwtAuthenticationConverter(keycloakJwtConverter()) ) ) // 处理认证异常:/api路径返回401,其他路径重定向登录 .exceptionHandling(ex -> ex .authenticationEntryPoint(new KeycloakAuthenticationEntryPoint()) ); return http.build(); } // 自定义JWT转换,提取Keycloak中的角色(按需添加) private JwtAuthenticationConverter keycloakJwtConverter() { JwtAuthenticationConverter converter = new JwtAuthenticationConverter(); converter.setJwtGrantedAuthoritiesConverter(new KeycloakRoleConverter()); return converter; } }
方式二:使用旧版KeycloakWebSecurityConfigurerAdapter(兼容老项目)
import org.keycloak.adapters.springsecurity.KeycloakSecurityComponents; import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider; import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper; import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy; import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; @Configuration @EnableWebSecurity @ComponentScan(basePackageClasses = KeycloakSecurityComponents.class) public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter { @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { KeycloakAuthenticationProvider authProvider = keycloakAuthenticationProvider(); authProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper()); auth.authenticationProvider(authProvider); } @Bean @Override protected SessionAuthenticationStrategy sessionAuthenticationStrategy() { return new NullAuthenticatedSessionStrategy(); } @Override protected void configure(HttpSecurity http) throws Exception { super.configure(http); http .authorizeRequests() .antMatchers("/login").permitAll() .antMatchers("/api/**").authenticated() .anyRequest().authenticated() .and() .exceptionHandling() .authenticationEntryPoint(new KeycloakAuthenticationEntryPoint()); } }
关键说明
- /login路径的作用:无需手动实现登录页面,当未认证用户访问需要登录的非/api路径时,Keycloak Adapter会自动重定向到Keycloak官方登录页,登录成功后跳转回原请求路径。
- Bearer Only模式的实现:
/api/**路径配置为authenticated(),结合资源服务器逻辑,会强制要求请求携带有效的Bearer Token,未携带/无效时直接返回401 Unauthorized,不会触发重定向。 - 客户端配置:确保Keycloak客户端的访问类型为
public或confidential,若为confidential需在配置中填写客户端密钥。
内容的提问来源于stack exchange,提问作者Ezekiela Rakotoarijaona
相关产品推荐
相关产品推荐

