我正在尝试使用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”并且令牌已成功生成,为什么会生成错误?
提前感谢您指出某些方向或帮助。
答案 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。