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

Spring Security中Authentication.getAuthorities()返回空集合问题

问题根源分析

你使用的是spring-boot-starter-oauth2-resource-server依赖,这套依赖的默认认证逻辑是直接解析JWT令牌获取用户信息,而非传统Spring Security中基于UserDetailsService从数据库加载用户权限的流程。你的UserServiceImpl里的loadUserByUsername方法根本没被执行,自然Authentication对象的权限集合是空的。

具体来说:

  • 资源服务器场景下,Spring Security默认会创建JwtAuthenticationToken作为认证对象,它的权限集合默认从JWT的scope/scp字段解析,而你的权限存在自定义的authorities字段中,默认不会被识别。
  • 你手动从Jwt对象中提取authorities字段能拿到值,是因为这只是直接读取JWT的原始内容,并非Spring Security认证流程中加载的权限。
解决方案

根据你的需求,可以选择两种配置方式:

方式一:直接从JWT的authorities字段解析权限

这种方式不需要调用UserDetailsService,直接让Spring Security从自定义JWT字段中提取权限,配置如下:

@Configuration
@ConditionalOnProperty(name = "davinci.security.enabled", havingValue = "true")
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .oauth2ResourceServer(oauth2 -> oauth2
                .jwt(jwt -> jwt
                    .jwtAuthenticationConverter(jwtAuthenticationConverter())
                )
            )
            .authorizeHttpRequests(auth -> auth
                .anyRequest().authenticated()
            );
        return http.build();
    }

    private Converter<Jwt, AbstractAuthenticationToken> jwtAuthenticationConverter() {
        JwtGrantedAuthoritiesConverter authoritiesConverter = new JwtGrantedAuthoritiesConverter();
        // 指定从JWT的"authorities"字段读取权限
        authoritiesConverter.setAuthoritiesClaimName("authorities");
        // 给权限添加前缀,方便和@PreAuthorize("hasRole('ADMIN')")配合使用
        authoritiesConverter.setAuthorityPrefix("ROLE_");

        JwtAuthenticationConverter jwtConverter = new JwtAuthenticationConverter();
        jwtConverter.setJwtGrantedAuthoritiesConverter(authoritiesConverter);
        return jwtConverter;
    }

    // 补充:需要配置JWT解码器,示例为对称密钥场景,根据你的授权服务器实际情况调整
    @Bean
    public JwtDecoder jwtDecoder() {
        return NimbusJwtDecoder.withSecretKey(
            new SecretKeySpec("your-jwt-secret-key".getBytes(), "HmacSHA256")
        ).build();
    }
}

配置完成后,authentication.getAuthorities()就能拿到转换后的GrantedAuthority(比如ROLE_ADMIN),你之前注释的权限判断代码就能正常工作。

方式二:结合UserDetailsService从数据库加载权限

如果需要从数据库动态获取用户权限(而非完全依赖JWT中的字段),可以配置让Spring Security在解析JWT后调用UserDetailsService加载权限:

@Configuration
@ConditionalOnProperty(name = "davinci.security.enabled", havingValue = "true")
public class SecurityConfig {

    private final UserDetailsService userDetailsService;

    public SecurityConfig(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .oauth2ResourceServer(oauth2 -> oauth2
                .authenticationProvider(jwtAuthenticationProvider())
            )
            .authorizeHttpRequests(auth -> auth
                .anyRequest().authenticated()
            );
        return http.build();
    }

    @Bean
    public JwtAuthenticationProvider jwtAuthenticationProvider() {
        JwtAuthenticationProvider provider = new JwtAuthenticationProvider(jwtDecoder());
        // 设置UserDetailsService,用于从数据库加载用户权限
        provider.setUserDetailsService(userDetailsService);
        // 配置权限合并策略:合并JWT自带权限和数据库加载的权限
        provider.setAuthoritiesMapper((jwtAuthorities, userDetails) -> {
            Collection<GrantedAuthority> combined = new ArrayList<>(jwtAuthorities);
            combined.addAll(userDetails.getAuthorities());
            return combined;
        });
        return provider;
    }

    @Bean
    public JwtDecoder jwtDecoder() {
        // 根据授权服务器配置调整解码器,示例为对称密钥场景
        return NimbusJwtDecoder.withSecretKey(
            new SecretKeySpec("your-jwt-secret-key".getBytes(), "HmacSHA256")
        ).build();
    }
}

注:如果JWT中存储的用户名是email而非默认的sub字段,还需要自定义JwtAuthenticationConverter将email作为用户名传入UserDetailsService。

内容的提问来源于stack exchange,提问作者Paul Marcelin Bejan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 20:35:18