使用Spring Boot和OAuth2获取此资源的范围不足

时间:2016-04-21 18:02:46

标签: api rest security spring-security-oauth2

我正在尝试使用Spring Boot 1.2.2为REST API运行一个小概念验证,并使用OAuth2进行保护。为此,我创建了两个项目,一个用于身份验证服务器,另一个用于REST服务。

在运行项目时,一切顺利。我从身份验证服务器获取一个令牌,然后使用该令牌,我设法调用该服务并获得预期的结果。

当我尝试验证服务中的范围时,会出现问题。只要我添加一行:

@PreAuthorize("#oauth2.hasScope('webshop')")

到我的服务,代码:

@RestController
public class ProductService {

    @RequestMapping("/product/{productId}")
    @PreAuthorize("#oauth2.hasScope('webshop')")
    public Product getProduct(@PathVariable int productId) {

        return new Product(productId, "name", 123);
    }
}

我收到了这个回复:

{
   "error": "insufficient_scope",
   "error_description": "Insufficient scope for this resource",
   "scope": "webshop"
}

身份验证服务器配置为:

@Configuration
@EnableAuthorizationServer
protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
            .withClient("acme")
            .secret("acmesecret")
            .authorizedGrantTypes("authorization_code", "refresh_token", "implicit", "password", "client_credentials")
            .scopes("webshop");
    }
}

这是获取令牌的实际调用:

juan@ubuntu:~/ms/core/product-service$ curl -s acme:acmesecret@localhost:9999/uaa/oauth/token -d grant_type=client_credentials -d scope=webshop
{
  "access_token": "ac3a9768-4ebb-44e3-a49f-21e2f117d0b4",
  "token_type": "bearer",
  "expires_in": 43199,
  "scope": "webshop"
}

然后,致电该服务:

juan@ubuntu:~/ms/core/product-service$ TOKEN=ac3a9768-4ebb-44e3-a49f-21e2f117d0b4
juan@ubuntu:~/ms/core/product-service$ curl 'http://localhost:8080/product/32' -H "Authorization: Bearer $TOKEN" -s
{
  "error": "insufficient_scope",
  "error_description": "Insufficient scope for this resource",
  "scope": "webshop"
}

我觉得由于缺乏一个概念,我只是缺少一些简单的东西。如果客户端已在内存中创建并且应该被允许执行“webshop”并且令牌已成功生成,为什么会生成错误?

提前感谢您指出某些方向或帮助。

1 个答案:

答案 0 :(得分:2)

这是由UserInfoTokenServices类无法从请求中提取范围而导致的,因此不会将它们添加到新的OAuth2Request中。

特别是这种方法

private OAuth2Authentication extractAuthentication(Map<String, Object> map) {
    Object principal = getPrincipal(map);
    List<GrantedAuthority> authorities = this.authoritiesExtractor
            .extractAuthorities(map);
    OAuth2Request request = new OAuth2Request(null, this.clientId, null, true, null,
            null, null, null, null);
    UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
            principal, "N/A", authorities);
    token.setDetails(map);
    return new OAuth2Authentication(request, token);
}

忽略从oauth2Request映射条目中提取作用域映射,然后将作用域集合的null传递给Oauth2Request作用域参数的构造函数。

这意味着即使您可能已将用户授权到特定范围,但是当通过security.oauth2.resource.userInfoUri端点查询authserver时,在调用代码中将忽略授权范围,因此PreAuthorize检查失败

这对我来说似乎是个错误;我已经提出了an issue on github