Keycloak与Spring Boot:实现按用户限制访问权限
实现Spring Boot + Keycloak按用户ID限制资源访问的方案
当然可以实现这种用户级的资源访问控制!你之前看到的角色权限是粗粒度的管控,而按用户ID匹配路径属于细粒度的资源隔离,不管是用KeycloakWebSecurityConfigurerAdapter还是新版本的Spring Security配置方式,都能轻松搞定。下面给你两种实用的实现方案:
方案一:方法级安全注解(简单直接)
这种方式适合在Controller层面精准控制单个接口,步骤非常简单:
- 先开启方法级安全支持,在你的Security配置类上加上
@EnableGlobalMethodSecurity(prePostEnabled = true); - 在对应的Controller方法上,用
@PreAuthorize注解编写SpEL表达式,匹配路径里的userId和当前认证用户的ID。
示例代码:
@RestController @RequestMapping("/api") public class UserProfileController { // 仅允许路径中的userId与当前登录用户ID一致时访问 @GetMapping("/{userId}/edit") @PreAuthorize("#userId == authentication.name") public ResponseEntity<String> editUserProfile(@PathVariable String userId) { // 你的业务逻辑代码 return ResponseEntity.ok("允许编辑用户 " + userId + " 的信息"); } }
注意:如果你的
userId对应Keycloak用户的唯一标识sub(而非用户名),需要调整表达式:@PreAuthorize("#userId == authentication.attributes['sub']")Keycloak会把用户的sub、用户名、邮箱等信息存入Authentication的attributes集合,你可以根据业务需求选择对应的属性。
方案二:全局URL规则配置(统一管控)
如果你想在Security配置里统一设置这类路径的访问规则,不用给每个Controller方法加注解,可以用HttpSecurity的access()方法结合SpEL表达式实现:
基于KeycloakWebSecurityConfigurerAdapter的配置(旧版本兼容)
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class KeycloakSecurityConfig extends KeycloakWebSecurityConfigurerAdapter { @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { KeycloakAuthenticationProvider authProvider = keycloakAuthenticationProvider(); // 转换Keycloak角色格式为Spring Security兼容的Authority authProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper()); auth.authenticationProvider(authProvider); } @Bean @Override protected SessionAuthenticationStrategy sessionAuthenticationStrategy() { return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl()); } @Bean public KeycloakConfigResolver keycloakConfigResolver() { // 读取Spring Boot配置文件中的Keycloak配置 return new KeycloakSpringBootConfigResolver(); } @Override protected void configure(HttpSecurity http) throws Exception { super.configure(http); http.authorizeRequests() // 针对/api/{userId}/edit路径设置权限规则 .antMatchers("/api/{userId}/edit") .access("#request.pathVariables['userId'] == authentication.name") // 其他接口的权限规则按需配置 .anyRequest().authenticated(); } }
新版本Spring Security(无WebSecurityConfigurerAdapter)
如果你的Spring Boot版本是2.7+(对应Spring Security 5.7+),WebSecurityConfigurerAdapter已被标记为废弃,推荐使用SecurityFilterChain的方式配置:
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig { private final KeycloakAuthenticationProvider keycloakAuthProvider; public SecurityConfig(KeycloakAuthenticationProvider keycloakAuthProvider) { this.keycloakAuthProvider = keycloakAuthProvider; } @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeRequests(auth -> auth .antMatchers("/api/{userId}/edit") .access("#request.pathVariables['userId'] == authentication.attributes['sub']") .anyRequest().authenticated() ) .authenticationProvider(keycloakAuthProvider) .oauth2ResourceServer(oauth2 -> oauth2.jwt()); return http.build(); } @Bean public KeycloakConfigResolver keycloakConfigResolver() { return new KeycloakSpringBootConfigResolver(); } }
额外注意事项
- 确保你的Keycloak客户端配置中开启了
openidscope,这样用户的sub、用户名等信息才会被正确传递到Spring Security的Authentication对象中; - 若需要自定义用户信息获取逻辑,可以实现
UserDetailsService或自定义KeycloakAuthenticationProvider来扩展。
内容的提问来源于stack exchange,提问作者Eneko
相关产品推荐
相关产品推荐

