您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

Spring Security:将OAuth2声明与角色映射以保护资源服务器端点

Spring Security:将OAuth2声明与角色映射以保护资源服务器端点

经过一番混乱之后,我找到了一个实现custom的解决方jwtAuthenticationConverter,该解决方案可以将特定于资源的角色添加到Authority集合中。

    http.oauth2ResourceServer()
                .jwt()
                .jwtAuthenticationConverter(new JwtAuthenticationConverter()
                {
                    @Override
                    protected Collection<GrantedAuthority> extractAuthorities(final Jwt jwt)
                    {
                        Collection<GrantedAuthority> authorities = super.extractAuthorities(jwt);
                        Map<String, Object> resourceAccess = jwt.getClaim("resource_access");
                        Map<String, Object> resource = null;
                        Collection<String> resourceRoles = null;
                        if (resourceAccess != null &&
                            (resource = (Map<String, Object>) resourceAccess.get("my-resource-id")) !=
                            null && (resourceRoles = (Collection<String>) resource.get("roles")) != null)
                            authorities.addAll(resourceRoles.stream()
                                                            .map(x -> new SimpleGrantedAuthority("ROLE_" + x))
                                                            .collect(Collectors.toSet()));
                        return authorities;
                    }
                });

其中 my-resource-id 既是出现在 resource_access 声明中的资源标识符,也是与ResourceServerSecurityConfigurer中 与API关联的值。

请注意,extractAuthorities它实际上已被弃用,因此应采用成熟的转换器来实现更面向未来的解决方

    import org.springframework.core.convert.converter.Converter;
    import org.springframework.security.authentication.AbstractAuthenticationToken;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.authority.SimpleGrantedAuthority;
    import org.springframework.security.oauth2.jwt.Jwt;
    import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
    import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;

    import java.util.Collection;
    import java.util.Collections;
    import java.util.Map;
    import java.util.stream.Collectors;
    import java.util.stream.Stream;

    public class CustomJwtAuthenticationConverter implements Converter<Jwt, AbstractAuthenticationToken>
    {
        private static Collection<? extends GrantedAuthority> extractResourceRoles(final Jwt jwt, final String resourceId)
        {
            Map<String, Object> resourceAccess = jwt.getClaim("resource_access");
            Map<String, Object> resource;
            Collection<String> resourceRoles;
            if (resourceAccess != null && (resource = (Map<String, Object>) resourceAccess.get(resourceId)) != null &&
                (resourceRoles = (Collection<String>) resource.get("roles")) != null)
                return resourceRoles.stream()
                                    .map(x -> new SimpleGrantedAuthority("ROLE_" + x))
                                    .collect(Collectors.toSet());
            return Collections.emptySet();
        }

        private final JwtGrantedAuthoritiesConverter defaultGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();

        private final String resourceId;

        public CustomJwtAuthenticationConverter(String resourceId)
        {
            this.resourceId = resourceId;
        }

        @Override
        public AbstractAuthenticationToken convert(final Jwt source)
        {
            Collection<GrantedAuthority> authorities = Stream.concat(defaultGrantedAuthoritiesConverter.convert(source)
                                                                                                       .stream(),
                                                                     extractResourceRoles(source, resourceId).stream())
                                                             .collect(Collectors.toSet());
            return new JwtAuthenticationToken(source, authorities);
        }
    }

我已经使用Spring Boot 2.1.9.RELEASE,Spring Security 5.2.0.RELEASE和官方的Keycloak 7.0.0 Docker镜像测试了这两种解决方案。

一般来说,我认为无论实际的授权服务器(即IdentityServer4,Keycloak …)如何,这似乎都是将声明转换为Spring Security授予的适当位置。

Java 2022/1/1 18:21:43 有531人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶