春季安全性:将OAuth2声明与角色进行映射以保护资源服务器端点

时间:2019-10-02 16:21:36

标签: spring rest spring-boot spring-security authorization

我正在使用Spring Boot设置资源服务器,并使用Spring Security提供的OAuth2保护端点。因此,我正在使用Spring Boot 2.1.8.RELEASE,例如,它使用Spring Security 5.1.6.RELEASE

作为授权服务器,我正在使用Keycloak。身份验证,颁发访问令牌和对资源服务器中的令牌进行验证之间的所有过程均正常运行。这是一个已发行和已解码令牌的示例(其中一些部分被删减):

{
  "jti": "5df54cac-8b06-4d36-b642-186bbd647fbf",
  "exp": 1570048999,
  "aud": [
    "myservice",
    "account"
  ],
  "azp": "myservice",
  "realm_access": {
    "roles": [
      "offline_access",
      "uma_authorization"
    ]
  },
  "resource_access": {
    "myservice": {
      "roles": [
        "ROLE_user",
        "ROLE_admin"
      ]
    },
    "account": {
      "roles": [
        "manage-account",
        "manage-account-links",
        "view-profile"
      ]
    }
  },
  "scope": "openid email offline_access microprofile-jwt profile address phone",
}

如何配置Spring Security以使用访问令牌中的信息为不同的端点提供条件授权?

最终我想编写一个像这样的控制器:

@RestController
public class Controller {

    @Secured("ROLE_user")
    @GetMapping("userinfo")
    public String userinfo() {
        return "not too sensitive action";
    }

    @Secured("ROLE_admin")
    @GetMapping("administration")
    public String administration() {
        return "TOOOO sensitive action";
    }
}

5 个答案:

答案 0 :(得分:4)

您遇到的困难部分是由于您的角色位于资源服务器->客户端 ID 下的 JWT 中。这需要一个自定义令牌转换器来提取它们。

您可以将 keycloak 配置为使用客户端映射器,该映射器将在顶级声明名称(例如“roles”)下显示角色。这使得 Spring Security 配置更简单,因为您只需要 JwtGrantedAuthoritiesConverter 并设置了 authorityClaimName,如@hillel_guy 所采用的方法所示。

keycloak 客户端映射器的配置如下:

enter image description here

答案 1 :(得分:3)

这是另一种解决方案

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

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .oauth2ResourceServer().jwt()
                .jwtAuthenticationConverter(jwtAuthenticationConverter());
    }

答案 2 :(得分:2)

经过一番摸索之后,我找到了一个实现自定义django-admin startproject的解决方案,该解决方案可以将特定于资源的角色附加到授权机构集合中。

jwtAuthenticationConverter

my-resource-id 既是 resource_access 声明中显示的资源标识符,也是 ResourceServerSecurityConfigurer 中与API关联的值em>。

请注意, 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; } }); 实际上已被弃用,因此,应采用成熟的转换器来实现更加面向未来的解决方案

extractAuthorities

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

一般来说,我想无论实际使用什么授权服务器(即IdentityServer4,Keycloak ...),这似乎都是将声明转换为Spring Security赠款的适当位置。

答案 3 :(得分:0)

正如@hillel_guy的答案已经提到的,使用AbstractHttpConfigurer应该是方法。通过spring-boot 2.3.4和spring-security 5.3.4,这对我来说是无缝的。 请参阅spring-security API文档以获取参考:OAuth2ResourceServerConfigurer

答案 4 :(得分:0)

如果您正在使用 Azure AD Oath,现在有一个更简单的方法:

        http 
        .cors()
        .and()
        .authorizeRequests()
        .anyRequest()
        .authenticated() 
        .and()
        .oauth2ResourceServer()
        .jwt()
        .jwtAuthenticationConverter(new AADJwtBearerTokenAuthenticationConverter("roles", "ROLE_")); 

ADDJwtBearerTokenAuthenticationConverter 允许您添加您的声明名称作为第一个参数,并将您希望角色的前缀添加为第二个参数。

我的导入以便您可以找到图书馆:

import com.azure.spring.aad.webapi.AADJwtBearerTokenAuthenticationConverter;