主题错误:
Authentication request failed: error="access_denied", error_description="Invalid token does not contain resource id (oauth2-resource)"
发博词
Spring Security OAuth2 架构上分为Authorization Server和Resource Server。我们可以为每一个Resource Server(一个微服务实例)设置一个resourceid。再给client授权的时候,可以设置这个client可以访问哪一些微服务实例,如果没设置,就是对所有的resource都有访问权限。
ResourceID在哪设置
在每个ResourceServer实例上设置。
配置文件
经测试,这个不管用,原因待查。
security:
enable-csrf: false
oauth2:
resource:
id: resource1
jwt:
key-uri: http://authorization-server:8080/oauth/token_key
filter-order: 3
ResourceServerConfigurerAdapter
@Configuration@EnableResourceServer@EnableOAuth2Client
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter{
// 改资源服务器id必须在数据库记录中有配置,也就是对应token的用户必须该资源访问权限(密文:test_resource_secret)
// 例如,我的数据库记录:'wx_takeout_client_id','test_resource_id','$2a$10$I28j9B0T/roapkMEqfIHguARt0GgLyXwC/DOnFwPpXuQ0xTkrd632','user_info','authorization_code,refresh_token,implicit,password','http://localhost:7010/uaa/login','ROLE_ADMIN,ROLE_DEVICE,ROLE_VIDEO',3600,7200,'{\"systemInfo\":\"Atlas System\"}','true'
// 通过授权模式或简化模式获取的token(对应用户为wx_takeout_client_id)具有访问资源服务器test_resource_id的权限,所以将改资源服务器id要与数据库的对应,否则无法访问
private static final String DEMO_RESOURCE_ID = "resource1";
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(DEMO_RESOURCE_ID).stateless(true);
}
}
ResourceID在哪验证
@EnableResourceServer会给Spring Security的FilterChan添加一个OAuth2AuthenticationProcessingFilter,OAuth2AuthenticationProcessingFilter会使用OAuth2AuthenticationManager来验证token。
OAuth2AuthenticationManager#authenticate(Authentication authentication)
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (authentication == null) {
throw new InvalidTokenException("Invalid token (token not found)");
}
String token = (String) authentication.getPrincipal();
OAuth2Authentication auth = tokenServices.loadAuthentication(token);
if (auth == null) {
throw new InvalidTokenException("Invalid token: " + token);
}
Collection<String> resourceIds = auth.getOAuth2Request().getResourceIds();
if (resourceId != null && resourceIds != null && !resourceIds.isEmpty() && !resourceIds.contains(resourceId)) {
throw new OAuth2AccessDeniedException("Invalid token does not contain resource id (" + resourceId + ")");
}
checkClientDetails(auth);
if (authentication.getDetails() instanceof OAuth2AuthenticationDetails) {
OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) authentication.getDetails();
// Guard against a cached copy of the same details
if (!details.equals(auth.getDetails())) {
// Preserve the authentication details from the one loaded by token services
details.setDecodedDetails(auth.getDetails());
}
}
auth.setDetails(authentication.getDetails());
auth.setAuthenticated(true);
return auth;
}
下面这段便是验证resourceid的地方;
Collection<String> resourceIds = auth.getOAuth2Request().getResourceIds();
if (resourceId != null && resourceIds != null && !resourceIds.isEmpty() && !resourceIds.contains(resourceId)) {
throw new OAuth2AccessDeniedException("Invalid token does not contain resource id (" + resourceId + ")");
}
注意
(1)在Spring Security的FilterChain中,OAuth2AuthenticationProcessingFilter在FilterSecurityInterceptor的前面,所以会先验证client有没有此resource的权限,只有在有此resource的权限的情况下,才会再去做进一步的判断;
(2)同时配置WebSecurity与ResourceServer的时候,也就是认证服务器和资源服务器在统一机器的时候,会导致授权码模式失效,最根本问题是WebSecurity与ResourceServer冲突,为解决改问题,只要给的配置都指定一个序号,websecurity的优先级高于ResourceServer才行,即WebSecurity的@Order(2)要小于ResourceServer
快来成为我的朋友或合作伙伴,一起交流,一起进步!
QQ群:961179337
微信:lixiang6153
邮箱:lixx2048@163.com
公众号:IT技术快餐
更多资料等你来拿!