You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Security全局方法安全不生效 集成Keycloak OAuth2报错排查

问题修复方案

错误根因说明

  • 调用findAll()接口报错:缺少spring-security-data依赖导致SecurityEvaluationContextExtension未生效,或是Spring版本兼容性问题,Repository层的SpEL表达式无法获取到Security上下文中的authentication对象
  • 调用add()接口403:Spring Security默认JWT转换器将Token中的sub字段作为用户名,而你的Token中实际用户名字段为user_name,导致@PreAuthorize("#workout.user == authentication.name")校验不通过

修复步骤

步骤1:补充依赖

首先确认项目引入了spring-security-data依赖,这是Security上下文在Repository层SpEL生效的前提:
Maven配置:

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-data</artifactId>
</dependency>

Gradle配置:

implementation 'org.springframework.security:spring-security-data'

步骤2:自定义JWT转换器,正确映射用户名和权限

你的Token中用户名字段为user_name、权限字段为authorities,和Spring默认映射规则不符,需要自定义转换器:
在ResourceServerConfig配置类中添加如下Bean:

@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
    JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
    // 指定权限读取字段
    grantedAuthoritiesConverter.setAuthoritiesClaimName("authorities");
    // 去掉默认的SCOPE_前缀
    grantedAuthoritiesConverter.setAuthorityPrefix("");

    JwtAuthenticationConverter authenticationConverter = new JwtAuthenticationConverter();
    authenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);
    // 指定用户名字段
    authenticationConverter.setPrincipalClaimName("user_name");
    return authenticationConverter;
}

修改HttpSecurity配置,关联自定义转换器:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
      .authorizeRequests(authz -> authz
        .mvcMatchers(HttpMethod.DELETE, "/**").hasAuthority("fitnessadmin")
        .anyRequest().authenticated())
      .oauth2ResourceServer(oauth2 -> oauth2
          .jwt(jwt -> jwt.jwtAuthenticationConverter(jwtAuthenticationConverter()))
      );
}

步骤3:优化查询逻辑(彻底解决Repository层SpEL报错)

为了避免不同Spring版本的Repository SpEL兼容性问题,建议把用户过滤逻辑移到Service层:
修改WorkoutRepository:

public interface WorkoutRepository extends JpaRepository<Workout, Integer> {
    List<Workout> findAllByUser(String user);
}

修改WorkoutService的findWorkouts方法:

public List<Workout> findWorkouts() {
    String currentUser = SecurityContextHolder.getContext().getAuthentication().getName();
    return repository.findAllByUser(currentUser);
}

步骤4:可选适配高版本Spring Security

如果你的Spring Boot版本>=2.7,@EnableGlobalMethodSecurity已废弃,可替换为新注解:

@EnableMethodSecurity(prePostEnabled = true)

内容的提问来源于stack exchange,提问作者Thomson Mathew

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 09:57:01