Spring Security 如何为特定声明结构配置JwtAuthenticationConverter?

46scxncf  于 2022-11-24  发布在  Spring
关注(0)|答案(1)|浏览(147)

我有一个JWT,其中的角色可以在一个特定的声明下找到。这个声明在一个嵌套结构中。我如何告诉JwtAuthenticationConverter在某个路径下找到角色?
作为Authorization-Server,我使用Keycloak。为角色添加一个Map器是可能的。但我现在想排除这种可能性,因为目标是在特定的声明下找到角色。
下面是我解码的JWT。角色“user-role”应该位于声明下面:“资源访问”-〉“用户”-〉“角色”:

"resource_access": {
    "admin": {
      "roles": [
        "admin-role"
      ]
    },
    "user": {
      "roles": [
        "user-role"
      ]
    },
    "account": {
      "roles": [
        "manage-account",
        "manage-account-links",
        "view-profile"
      ]
    }
  },

下面是我对JwtAuthenticationConverter的配置:

@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
{
    @Override
    public void configure(HttpSecurity http) throws Exception
    {
        http.authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
                .oauth2ResourceServer()
                .jwt()
                .jwtAuthenticationConverter(jwtAuthenticationConverter());
    }

    private static JwtAuthenticationConverter jwtAuthenticationConverter()
    {
        var jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
        jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName("resource_access.user.roles");
        jwtGrantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");
        var jwtAuthenticationConverter = new JwtAuthenticationConverter();
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter);
        return jwtAuthenticationConverter;
    }
}

我希望有人能帮助我。谢谢:)

cyvaqqii

cyvaqqii1#

谢谢你的帮助。2解决方案是实现一个自定义的转换器。
下面是我的解决方案:
我的自定义转换器:

@AllArgsConstructor
public class KeycloakJwtAuthenticationConverter implements Converter<Jwt, AbstractAuthenticationToken>
{
    @NotEmpty
    private List<String> clientIds;

    @Override
    public AbstractAuthenticationToken convert(Jwt source)
    {
        return new JwtAuthenticationToken(source, Stream.concat(new JwtGrantedAuthoritiesConverter().convert(source)
                .stream(), extractResourceRoles(source).stream())
                .collect(toSet()));
    }

    private Collection<? extends GrantedAuthority> extractResourceRoles(Jwt jwt)
    {
        var resourceAccess = new HashMap<>(jwt.getClaim("resource_access"));
        var resourceRoles = new ArrayList<>();

        clientIds.stream().forEach(id ->
        {
            if (resourceAccess.containsKey(id))
            {
                var resource = (Map<String, List<String>>) resourceAccess.get(id);
                resource.get("roles").forEach(role -> resourceRoles.add(id + "_" + role));
            }
        });
        return resourceRoles.isEmpty() ? emptySet() : resourceRoles.stream().map(r -> new SimpleGrantedAuthority("ROLE_" + r)).collect(toSet());
    }
}

我的安全配置:

@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
{
    @Value("${spring.security.jwt.role.locations}")
    private List<String> rolesLocation;

    @Override
    public void configure(HttpSecurity http) throws Exception
    {
        http.authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
                .oauth2ResourceServer()
                .jwt()
                .jwtAuthenticationConverter(new KeycloakJwtAuthenticationConverter(rolesLocation));
    }
}

相关问题