OAuth2AuthenticationManager源碼跟蹤


本文僅助那些在Security集成OAuth2.0路上踩坑的人理解認證過程。

OAuth2AuthenticationManager

首先,我覺得分析OAuth2AuthenticationManager,我們需要先理解它是如何被使用,何時被使用,那我們就從這里開始逐一分析吧,我手畫了一張圖作為索引,以便我們理解,其中藍色的為類,綠色的為接口,箭頭指向的方向是實現類或者父類。

因為里面接口和方法過多,所以不做展示,下面具體來進行代碼分析。

 public class OAuth2AuthenticationManager implements AuthenticationManager, InitializingBean {

	private ResourceServerTokenServices tokenServices;

	private ClientDetailsService clientDetailsService;

	private String resourceId;

	public void setResourceId(String resourceId) {
		this.resourceId = resourceId;
	}

	public void setClientDetailsService(ClientDetailsService clientDetailsService) {
		this.clientDetailsService = clientDetailsService;
	}

	public void setTokenServices(ResourceServerTokenServices tokenServices) {
		this.tokenServices = tokenServices;
	}

	public void afterPropertiesSet() {
		Assert.state(tokenServices != null, "TokenServices are required");
	}

(3)	public Authentication authenticate(Authentication authentication) throws AuthenticationException {

		if (authentication == null) {
			throw new InvalidTokenException("Invalid token (token not found)");
		}
(3).1		String token = (String) authentication.getPrincipal();
(3).2		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 + ")");
		}

(3).3		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());
(3).4		auth.setAuthenticated(true);
		return auth;

	}

	private void checkClientDetails(OAuth2Authentication auth) {
		if (clientDetailsService != null) {
			ClientDetails client;
			try {
				client = clientDetailsService.loadClientByClientId(auth.getOAuth2Request().getClientId());
			}
			catch (ClientRegistrationException e) {
				throw new OAuth2AccessDeniedException("Invalid token contains invalid client id");
			}
			Set<String> allowed = client.getScope();
			for (String scope : auth.getOAuth2Request().getScope()) {
				if (!allowed.contains(scope)) {
					throw new OAuth2AccessDeniedException(
							"Invalid token contains disallowed scope (" + scope + ") for this client");
				}
			}
		}
	}

}

OAuth2AuthenticationManager的成員變量

ResourceServerTokenServices

以上是它的關系圖,關於該接口,了解即可,不必過於深究,有興趣的小伙伴們可以去翻看源碼,學習一下代碼結構也是不錯的。
DefaultTokenServices 利用Security內置的令牌存儲器(Tokenstore)接口進行數據庫的CRUD操作,查看數據庫結構及表說明

ClientDetailsService


ClientDetailsService 用於加載客戶端,有兩種實現方式,一種是基於內存,一種是基於存儲庫的方式。

auth-server: http://localhost:18081/uac
server:
  port: 18082

security:
  oauth2:
    client:
      client-id: client1
      client-secret: 201314
      user-authorization-uri: ${auth-server}/oauth/authorize
      access-token-uri: ${auth-server}/oauth/token
    resource:
      jwt:
        key-uri: ${auth-server}/oauth/token_key
        key-value: 201314

上面是關於客戶端的配置,auth-server 為資源服務器路徑。

authenticate()

  • (3).1處的代碼,期望傳入的身份驗證請求具有一個主體值,該主體值是一個訪問令牌值(一般在(authorization header)請求頭中)
  • (3).2處的代碼,ResourceServerTokenServices通過查詢數據庫中 oauth_client_details該表,加載身份驗證。
  • (3).3處的代碼,檢查資源id是否包含在授權請求中。
  • (3).4,通過身份認證,Security將OAuth2Authentication對象存入Session中,然后跳轉到AuthorizationEndpointauthorize()。該方法跳出一個授權頁面,提供授權的通過權或否決權。

以上就是我對於OAuth2AuthenticationManager源碼的理解,僅供參考,如有不正確的地方,請提出指正。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM