一、resource_id的作用
Spring Security OAuth2 架構上分為Authorization Server認證伺服器和Resource Server資源伺服器。我們可以為每一個Resource Server(一個微服務例項)設定一個resourceid。Authorization Server給client第三方客戶端授權的時候,可以設定這個client可以訪問哪一些Resource Server資源服務,如果沒設定,就是對所有的Resource Server都有訪問許可權。
二、ResourceServer如何設定ResourceID
在每個ResourceServer例項上設定resourceId,該resourceId作為該服務資源的唯一標識。(假如同一個微服務資源部署多份,resourceId相同)
@Configuration
@EnableResourceServer
public class OAuth2ResourceServer extends ResourceServerConfigurerAdapter {
private static final String DEMO_RESOURCE_ID = "test-resource";
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(DEMO_RESOURCE_ID)
//...... 還可以有有其他的配置
}
}
三、AuthorizationServer如何設定ResourceIDs
在AuthorizationServer為客戶端client配置ResourceID的目的是:限制某個client可以訪問的資源服務。
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
//配置客戶端儲存到db 代替原來得記憶體模式
JdbcClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
clientDetailsService.setPasswordEncoder(passwordEncoder);
clients.withClientDetails(clientDetailsService);
}
這裡需要使用JdbcClientDetailsService類和資料庫表oauth_client_details進行配置的持久化儲存,以及動態配置。
三、ResourceID在哪驗證
ResourceID當然是在Resource Server資源伺服器進行驗證(你能不能訪問我的資源,當然由我自己來驗證)。當資源請求傳送到Resource Server的時候會攜帶access_token,Resource Server會根據access_token找到client_id,進而找到該client可以訪問的resource_ids。如果resource_ids包含ResourceServer自己設定ResourceID,這關就過去了,就可以繼續進行其他的許可權驗證。
- @EnableResourceServer會給Spring Security的FilterChan新增一個OAuth2AuthenticationProcessingFilter過濾器,過濾所有的資源請求。
- OAuth2AuthenticationProcessingFilter會使用OAuth2AuthenticationManager來驗證token。驗證Token的時候會去oauth_client_details表載入client配置資訊。
如果AuthorizationServer認證client1可以訪問test-resource,但client1去訪問了oauth-rs,會響應如下資訊:
{"error":"access_denied","error_description":"Invalid token does not contain resource id (oauth-rs)"}
具體實現resource_id驗證的原始碼: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 + ")");
}
在Spring Security的FilterChain中,OAuth2AuthenticationProcessingFilter在FilterSecurityInterceptor的前面,所以會先驗證client有沒有此resource的許可權,只有在有此resource的許可權的情況下,才會再去做進一步的進行其他驗證的判斷。
歡迎關注我的部落格,裡面有很多精品合集
- 本文轉載註明出處(必須帶連線,不能只轉文字):字母哥部落格。
覺得對您有幫助的話,幫我點贊、分享!您的支援是我不竭的創作動力! 。另外,筆者最近一段時間輸出瞭如下的精品內容,期待您的關注。