首页 > 解决方案 > Spring Security:提取 oidc 角色声明给 Spring 当局

问题描述

我正在尝试从一个OAuth2AuthenticationToken被检测为 Spring Security 权限的角色声明。在 OIDC 提供方(在我的情况下为 Azure AD)定义了一个自定义角色,该角色嵌套在 中DefaultOidcUser,但不会自动添加到权限中: 在此处输入图像描述

我试图像这样从 Jwt 令牌中提取它们

但是,当我这样做时,不会调用以下方法(无论是在登录期间,还是在以后,即使在默认配置中):

我目前的配置是:

@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()
            <some more config that has nothing to do with oauth/oidc>
            .and()
            .oauth2Login()
            .and()
            .oauth2ResourceServer()
            .jwt()
            .jwtAuthenticationConverter(jwtAuthenticationConverter())
            .and()
            .and()
            .oauth2Client()
        ;
    }

    private JwtAuthenticationConverter jwtAuthenticationConverter() {
        // create a custom JWT converter to map the roles from the token as granted authorities
        JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
        jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName("roles");     
        JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter);
        return jwtAuthenticationConverter;
    }
}

我也尝试过

CustomJwtAuthConverter implements Converter<Jwt, AbstractAuthenticationToken>

但无济于事。

任何帮助,将不胜感激。

标签: javaspring-securityjhipsteropenid-connect

解决方案


管理使用权限映射器来实现它,该映射器还从 oidcToken 中提取声明:

public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    
    [...]
   
    @Bean
    public GrantedAuthoritiesMapper userAuthoritiesMapper() {
        return authorities -> {
            Set<GrantedAuthority> mappedAuthorities = new HashSet<>();

            authorities.forEach(
                authority -> {
                    // Check for OidcUserAuthority because Spring Security 5.2 returns
                    // each scope as a GrantedAuthority, which we don't care about.
                    if (authority instanceof OidcUserAuthority) {
                        OidcUserAuthority oidcUserAuthority = (OidcUserAuthority) authority;
                        mappedAuthorities.addAll(SecurityUtils.extractAuthorityFromClaims(oidcUserAuthority.getUserInfo().getClaims()));
                        mappedAuthorities.addAll(SecurityUtils.extractAuthorityFromClaims(oidcUserAuthority.getIdToken().getClaims()));
                    }
                }
            );
            return mappedAuthorities;
        };
    }

}

在 SecurityUtils 内部:

public static List<GrantedAuthority> extractAuthorityFromClaims(Map<String, Object> claims) {
        return mapRolesToGrantedAuthorities(getRolesFromClaims(claims));
    }
private static List<GrantedAuthority> mapRolesToGrantedAuthorities(Collection<String> roles) {
        return roles.stream().filter(role -> role.startsWith("ROLE_")).map(SimpleGrantedAuthority::new).collect(Collectors.toList());
    }

之后,自定义角色应该出现在 mappedAuthorities 中,并与它一起出现在令牌的权限中。因此可以使用注释“hasRole”和“hasAuthority”。


推荐阅读