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

Spring Security 如何提取OIDC的role claims转换为Spring Authorities?

根本原因

你配置的JwtAuthenticationConverter系列组件属于Spring Security OAuth2资源服务器模块,仅会在处理携带Authorization: Bearer {JWT}的接口请求时触发。你走oauth2Login的OIDC授权码登录流程时,用户身份会被封装为DefaultOidcUser,这套登录流程和资源服务器的JWT解析逻辑完全独立,所以你写的转换器永远不会被调用。

解决方案

你需要自定义OidcUserService,在加载OIDC用户信息的阶段,从Azure AD返回的claims中提取自定义角色,拼接到Spring Security的权限列表中,具体实现如下:

  1. 自定义OidcUserService实现类
import org.springframework.security.oauth2.core.oidc.OidcUser;
import org.springframework.security.oauth2.core.oidc.user.OidcUserService;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class CustomOidcUserService extends OidcUserService {
    @Override
    public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException {
        OidcUser originalOidcUser = super.loadUser(userRequest);
        // 从Azure AD返回的claims中提取自定义角色
        List<String> roles = originalOidcUser.getClaimAsStringList("roles");
        roles = roles == null ? Collections.emptyList() : roles;
        // 拼接原有权限和自定义角色,可根据需求调整角色前缀规则
        List<GrantedAuthority> mergedAuthorities = Stream.concat(
                originalOidcUser.getAuthorities().stream(),
                roles.stream().map(role -> new SimpleGrantedAuthority("ROLE_" + role))
        ).collect(Collectors.toList());
        // 返回携带完整权限的OidcUser
        return new DefaultOidcUser(mergedAuthorities, originalOidcUser.getIdToken(), originalOidcUser.getUserInfo());
    }
}
  1. 修改安全配置,将自定义实现注册到oauth2Login流程中
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@Import(SecurityProblemSupport.class)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        // @formatter:off
        http
            .csrf()
            // 你原有和oauth/oidc无关的配置保留
            .and()
            .oauth2Login()
            // 新增自定义OidcUserService配置
            .userInfoEndpoint()
            .oidcUserService(customOidcUserService())
            .and()
            .and()
            .oauth2ResourceServer()
            .jwt()
            .jwtAuthenticationConverter(jwtAuthenticationConverter())
            .and()
            .and()
            .oauth2Client();
        // @formatter:on
    }

    private CustomOidcUserService customOidcUserService() {
        return new CustomOidcUserService();
    }

    // 你原有jwtAuthenticationConverter方法保留,用于资源服务器场景
    private JwtAuthenticationConverter jwtAuthenticationConverter() {
        JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
        jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName("roles");
        JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter);
        return jwtAuthenticationConverter;
    }
}

补充说明

如果你同时需要支持页面登录、第三方客户端持JWT调用接口两种场景,保留原有资源服务器JWT转换器配置即可,注意两边的角色前缀、映射规则保持一致。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 05:12:01