Spring Security OAuth2 Source code analysis

OAuth 2 Developers Guide:https://projects.spring.io/spring-security-oauth/docs/oauth2.htmlhtml

OAuth 2.0 Provider Implementation

@EnableAuthorizationServer Annotation

The @EnableAuthorizationServer statement is as follows:java

/**
 * Convenience annotation for enabling an Authorization Server (i.e. an {@link AuthorizationEndpoint} and a
 * {@link TokenEndpoint}) in the current application context, which must be a {@link DispatcherServlet} context. Many
 * features of the server can be customized using <code>@Beans</code> of type {@link AuthorizationServerConfigurer}
 * (e.g. by extending {@link AuthorizationServerConfigurerAdapter}). The user is responsible for securing the
 * Authorization Endpoint (/oauth/authorize) using normal Spring Security features ({@link EnableWebSecurity
 * &#064;EnableWebSecurity} etc.), but the Token Endpoint (/oauth/token) will be automatically secured using HTTP Basic
 * authentication on the client's credentials. Clients <em>must</em> be registered by providing a
 * {@link ClientDetailsService} through one or more AuthorizationServerConfigurers.
 * 
 * @author Dave Syer
 * 
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AuthorizationServerEndpointsConfiguration.class, AuthorizationServerSecurityConfiguration.class})
public @interface EnableAuthorizationServer {

}

  enable authorization Server(AuthorizationEndpoint(受權端點)和TokenEndpoint(令牌端點)),通常設置在extends AuthorizationServerConfigurerAdapter的類。spring

  經過一個或多個AuthprizationServerConfigurers提供一個ClientDetailService來註冊客戶端。服務器

該註解同時會啓用AuthorizationEndpoint和TokenEndpoint,而且須要在DispatcherServlet上下文。app

AuthorizationServerConfigurer

The @AuthorizationServerConfigurer statement is as follows:less

/**
 * Convenient strategy for configuring an OAUth2 Authorization Server. Beans of this type are applied to the Spring
 * context automatically if you {@link EnableAuthorizationServer @EnableAuthorizationServer}.
 * 
 * @author Dave Syer
 * 
 */
public interface AuthorizationServerConfigurer {

	/**
	 * Configure the security of the Authorization Server, which means in practical terms the /oauth/token endpoint. The
	 * /oauth/authorize endpoint also needs to be secure, but that is a normal user-facing endpoint and should be
	 * secured the same way as the rest of your UI, so is not covered here. The default settings cover the most common
	 * requirements, following recommendations from the OAuth2 spec, so you don't need to do anything here to get a
	 * basic server up and running.
	 * 
	 * @param security a fluent configurer for security features
	 */
	void configure(AuthorizationServerSecurityConfigurer security) throws Exception;

	/**
	 * Configure the {@link ClientDetailsService}, e.g. declaring individual clients and their properties. Note that
	 * password grant is not enabled (even if some clients are allowed it) unless an {@link AuthenticationManager} is
	 * supplied to the {@link #configure(AuthorizationServerEndpointsConfigurer)}. At least one client, or a fully
	 * formed custom {@link ClientDetailsService} must be declared or the server will not start.
	 * 
	 * @param clients the client details configurer
	 */
	void configure(ClientDetailsServiceConfigurer clients) throws Exception;

	/**
	 * Configure the non-security features of the Authorization Server endpoints, like token store, token
	 * customizations, user approvals and grant types. You shouldn't need to do anything by default, unless you need
	 * password grants, in which case you need to provide an {@link AuthenticationManager}.
	 * 
	 * @param endpoints the endpoints configurer
	 */
	void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception;

}

  服務器會使用AuthorizationServerConfigurer類型的Bean對象。某些功能能夠經過擴展AuthorizationServerConfigurerAdapter implementation。AuthorizationServerConfigurerAdapter類是適配器類,實現了AuthorizationServerConfigurer接口,提供空實現。dom

TheAuthorizationServerConfigurerAdapter statement is as follows:ide

public class AuthorizationServerConfigurerAdapter implements AuthorizationServerConfigurer {

	@Override
	public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
	}

	@Override
	public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
	}

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

}

  AuthorizationServerConfigurer interface default implementation class:OAuth2AuthorizationServerConfiguration。post

OAuth2AuthprizationServerConfiguration

  OAuth2AuthprizationServerConfiguration statement is as follows:ui

/**
 * Configuration for a Spring Security OAuth2 authorization server. Back off if another
 * {@link AuthorizationServerConfigurer} already exists or if authorization server is not
 * enabled.
 *
 * @author Greg Turnquist
 * @author Dave Syer
 * @since 1.3.0
 */
@Configuration
@ConditionalOnClass(EnableAuthorizationServer.class)
@ConditionalOnMissingBean(AuthorizationServerConfigurer.class)
@ConditionalOnBean(AuthorizationServerEndpointsConfiguration.class)
@EnableConfigurationProperties(AuthorizationServerProperties.class)
public class OAuth2AuthorizationServerConfiguration
		extends AuthorizationServerConfigurerAdapter {

	private static final Log logger = LogFactory
			.getLog(OAuth2AuthorizationServerConfiguration.class);

	@Autowired
	private BaseClientDetails details;

	@Autowired
	private AuthenticationManager authenticationManager;

	@Autowired(required = false)
	private TokenStore tokenStore;

	@Autowired
	private AuthorizationServerProperties properties;

	@Override
	public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
		ClientDetailsServiceBuilder<InMemoryClientDetailsServiceBuilder>.ClientBuilder builder = clients
				.inMemory().withClient(this.details.getClientId());
		builder.secret(this.details.getClientSecret())
				.resourceIds(this.details.getResourceIds().toArray(new String[0]))
				.authorizedGrantTypes(
						this.details.getAuthorizedGrantTypes().toArray(new String[0]))
				.authorities(
						AuthorityUtils.authorityListToSet(this.details.getAuthorities())
								.toArray(new String[0]))
				.scopes(this.details.getScope().toArray(new String[0]));

		if (this.details.getAutoApproveScopes() != null) {
			builder.autoApprove(
					this.details.getAutoApproveScopes().toArray(new String[0]));
		}
		if (this.details.getAccessTokenValiditySeconds() != null) {
			builder.accessTokenValiditySeconds(
					this.details.getAccessTokenValiditySeconds());
		}
		if (this.details.getRefreshTokenValiditySeconds() != null) {
			builder.refreshTokenValiditySeconds(
					this.details.getRefreshTokenValiditySeconds());
		}
		if (this.details.getRegisteredRedirectUri() != null) {
			builder.redirectUris(
					this.details.getRegisteredRedirectUri().toArray(new String[0]));
		}
	}

	@Override
	public void configure(AuthorizationServerEndpointsConfigurer endpoints)
			throws Exception {
		if (this.tokenStore != null) {
			endpoints.tokenStore(this.tokenStore);
		}
		if (this.details.getAuthorizedGrantTypes().contains("password")) {
			endpoints.authenticationManager(this.authenticationManager);
		}
	}

	@Override
	public void configure(AuthorizationServerSecurityConfigurer security)
			throws Exception {
		if (this.properties.getCheckTokenAccess() != null) {
			security.checkTokenAccess(this.properties.getCheckTokenAccess());
		}
		if (this.properties.getTokenKeyAccess() != null) {
			security.tokenKeyAccess(this.properties.getTokenKeyAccess());
		}
		if (this.properties.getRealm() != null) {
			security.realm(this.properties.getRealm());
		}
	}

	@Configuration
	protected static class ClientDetailsLogger {

		@Autowired
		private OAuth2ClientProperties credentials;

		@PostConstruct
		public void init() {
			String prefix = "security.oauth2.client";
			boolean defaultSecret = this.credentials.isDefaultSecret();
			logger.info(String.format(
					"Initialized OAuth2 Client\n\n%s.clientId = %s\n%s.secret = %s\n\n",
					prefix, this.credentials.getClientId(), prefix,
					defaultSecret ? this.credentials.getClientSecret() : "****"));
		}

	}

	@Configuration
	@ConditionalOnMissingBean(BaseClientDetails.class)
	protected static class BaseClientDetailsConfiguration {

		@Autowired
		private OAuth2ClientProperties client;

		@Bean
		@ConfigurationProperties("security.oauth2.client")
		public BaseClientDetails oauth2ClientDetails() {
			BaseClientDetails details = new BaseClientDetails();
			if (this.client.getClientId() == null) {
				this.client.setClientId(UUID.randomUUID().toString());
			}
			details.setClientId(this.client.getClientId());
			details.setClientSecret(this.client.getClientSecret());
			details.setAuthorizedGrantTypes(Arrays.asList("authorization_code",
					"password", "client_credentials", "implicit", "refresh_token"));
			details.setAuthorities(
					AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER"));
			details.setRegisteredRedirectUri(Collections.<String>emptySet());
			return details;
		}

	}

}

當上下文中不存在AuthorizationServerConfigurer接口的實現時,將默認使用OAuth2AuthorizationServerConfiguration實現,默認的服務器受權配置類。

在@EnableAuthorizationServer該註解中有如下註解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AuthorizationServerEndpointsConfiguration.class, AuthorizationServerSecurityConfiguration.class})
public @interface EnableAuthorizationServer {}

 

AuthorizationServerEndPointsConfiguration

@Configuration
@Import(TokenKeyEndpointRegistrar.class)
public class AuthorizationServerEndpointsConfiguration {

	private AuthorizationServerEndpointsConfigurer endpoints = new AuthorizationServerEndpointsConfigurer();

	@Autowired
	private ClientDetailsService clientDetailsService;

	@Autowired
	private List<AuthorizationServerConfigurer> configurers = Collections.emptyList();

	@PostConstruct
	public void init() {
		for (AuthorizationServerConfigurer configurer : configurers) {
			try {
				configurer.configure(endpoints);
			} catch (Exception e) {
				throw new IllegalStateException("Cannot configure enpdoints", e);
			}
		}
		endpoints.setClientDetailsService(clientDetailsService);
	}

	@Bean
	public AuthorizationEndpoint authorizationEndpoint() throws Exception {
		AuthorizationEndpoint authorizationEndpoint = new AuthorizationEndpoint();
		FrameworkEndpointHandlerMapping mapping = getEndpointsConfigurer().getFrameworkEndpointHandlerMapping();
		authorizationEndpoint.setUserApprovalPage(extractPath(mapping, "/oauth/confirm_access"));
		authorizationEndpoint.setProviderExceptionHandler(exceptionTranslator());
		authorizationEndpoint.setErrorPage(extractPath(mapping, "/oauth/error"));
		authorizationEndpoint.setTokenGranter(tokenGranter());
		authorizationEndpoint.setClientDetailsService(clientDetailsService);
		authorizationEndpoint.setAuthorizationCodeServices(authorizationCodeServices());
		authorizationEndpoint.setOAuth2RequestFactory(oauth2RequestFactory());
		authorizationEndpoint.setOAuth2RequestValidator(oauth2RequestValidator());
		authorizationEndpoint.setUserApprovalHandler(userApprovalHandler());
		return authorizationEndpoint;
	}

	@Bean
	public TokenEndpoint tokenEndpoint() throws Exception {
		TokenEndpoint tokenEndpoint = new TokenEndpoint();
		tokenEndpoint.setClientDetailsService(clientDetailsService);
		tokenEndpoint.setProviderExceptionHandler(exceptionTranslator());
		tokenEndpoint.setTokenGranter(tokenGranter());
		tokenEndpoint.setOAuth2RequestFactory(oauth2RequestFactory());
		tokenEndpoint.setOAuth2RequestValidator(oauth2RequestValidator());
		tokenEndpoint.setAllowedRequestMethods(allowedTokenEndpointRequestMethods());
		return tokenEndpoint;
	}

	@Bean
	public CheckTokenEndpoint checkTokenEndpoint() {
		CheckTokenEndpoint endpoint = new CheckTokenEndpoint(getEndpointsConfigurer().getResourceServerTokenServices());
		endpoint.setAccessTokenConverter(getEndpointsConfigurer().getAccessTokenConverter());
		endpoint.setExceptionTranslator(exceptionTranslator());
		return endpoint;
	}

	@Bean
	public WhitelabelApprovalEndpoint whitelabelApprovalEndpoint() {
		return new WhitelabelApprovalEndpoint();
	}

	@Bean
	public WhitelabelErrorEndpoint whitelabelErrorEndpoint() {
		return new WhitelabelErrorEndpoint();
	}

	@Bean
	public FrameworkEndpointHandlerMapping oauth2EndpointHandlerMapping() throws Exception {
		return getEndpointsConfigurer().getFrameworkEndpointHandlerMapping();
	}

	@Bean
	public ConsumerTokenServices consumerTokenServices() throws Exception {
		return getEndpointsConfigurer().getConsumerTokenServices();
	}

	/**
	 * This needs to be a <code>@Bean</code> so that it can be
	 * <code>@Transactional</code> (in case the token store supports them). If
	 * you are overriding the token services in an
	 * {@link AuthorizationServerConfigurer} consider making it a
	 * <code>@Bean</code> for the same reason (assuming you need transactions,
	 * e.g. for a JDBC token store).
	 * 
	 * @return an AuthorizationServerTokenServices
	 */
	@Bean
	public AuthorizationServerTokenServices defaultAuthorizationServerTokenServices() {
		return endpoints.getDefaultAuthorizationServerTokenServices();
	}

	public AuthorizationServerEndpointsConfigurer getEndpointsConfigurer() {
		if (!endpoints.isTokenServicesOverride()) {
			endpoints.tokenServices(defaultAuthorizationServerTokenServices());
		}
		return endpoints;
	}

	private Set<HttpMethod> allowedTokenEndpointRequestMethods() {
		return getEndpointsConfigurer().getAllowedTokenEndpointRequestMethods();
	}

	private OAuth2RequestFactory oauth2RequestFactory() throws Exception {
		return getEndpointsConfigurer().getOAuth2RequestFactory();
	}

	private UserApprovalHandler userApprovalHandler() throws Exception {
		return getEndpointsConfigurer().getUserApprovalHandler();
	}

	private OAuth2RequestValidator oauth2RequestValidator() throws Exception {
		return getEndpointsConfigurer().getOAuth2RequestValidator();
	}

	private AuthorizationCodeServices authorizationCodeServices() throws Exception {
		return getEndpointsConfigurer().getAuthorizationCodeServices();
	}

	private WebResponseExceptionTranslator exceptionTranslator() {
		return getEndpointsConfigurer().getExceptionTranslator();
	}

	private TokenGranter tokenGranter() throws Exception {
		return getEndpointsConfigurer().getTokenGranter();
	}

	private String extractPath(FrameworkEndpointHandlerMapping mapping, String page) {
		String path = mapping.getPath(page);
		if (path.contains(":")) {
			return path;
		}
		return "forward:" + path;
	}

	@Configuration
	protected static class TokenKeyEndpointRegistrar implements BeanDefinitionRegistryPostProcessor {

		private BeanDefinitionRegistry registry;

		@Override
		public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
			String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory,
					JwtAccessTokenConverter.class, false, false);
			if (names.length > 0) {
				BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(TokenKeyEndpoint.class);
				builder.addConstructorArgReference(names[0]);
				registry.registerBeanDefinition(TokenKeyEndpoint.class.getName(), builder.getBeanDefinition());
			}
		}

		@Override
		public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
			this.registry = registry;
		}

	}

}

 

TokenKeyEndpointRegistrar

 Register tokenkey endpoint.

@Configuration
	protected static class TokenKeyEndpointRegistrar implements BeanDefinitionRegistryPostProcessor {

		private BeanDefinitionRegistry registry;

		@Override
		public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
			String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory,
					JwtAccessTokenConverter.class, false, false);
			if (names.length > 0) {
				BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(TokenKeyEndpoint.class);
				builder.addConstructorArgReference(names[0]);
				registry.registerBeanDefinition(TokenKeyEndpoint.class.getName(), builder.getBeanDefinition());
			}
		}

		@Override
		public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
			this.registry = registry;
		}

	}

  判斷上下文中是否存在JwtAccessTokenConverter的Bean對象,若是存在的話獲取全部該類型的Bean類型的name,若是大於0的話,經過BeanDefinitionBuilder生成TokenKeyEndpoint的BeanDefinitionBuilder。而後經過addConstructorArgReference方法,將該name[0]的對象,做爲構造參數傳遞至TokenKeyEndpoint類,而且在context中註冊該對象。

 

public class AuthorizationServerEndpointsConfiguration {

	private AuthorizationServerEndpointsConfigurer endpoints = new AuthorizationServerEndpointsConfigurer();

	@Autowired
	private ClientDetailsService clientDetailsService;

	@Autowired
	private List<AuthorizationServerConfigurer> configurers = Collections.emptyList();

	@PostConstruct
	public void init() {
		for (AuthorizationServerConfigurer configurer : configurers) {
			try {
				configurer.configure(endpoints);
			} catch (Exception e) {
				throw new IllegalStateException("Cannot configure enpdoints", e);
			}
		}
		endpoints.setClientDetailsService(clientDetailsService);
	}
   ....
}

  注入全部AuthorizationServerConfigurer的implementation,即繼承AuthorizationServerConfigurerAdapter的類。

configurer.configure(endpoints);

傳遞的對象爲private AuthorizationServerEndpointsConfigurer endpoints = new AuthorizationServerEndpointsConfigurer();

AuthorizationServerEndpointsConfigurer  statement is as follows:

/**
 * Configure the properties and enhanced functionality of the Authorization Server endpoints.
 */
public final class AuthorizationServerEndpointsConfigurer {
  ...
}

也就是調用如下方法。

/**
	 * Configure the non-security features of the Authorization Server endpoints, like token store, token
	 * customizations, user approvals and grant types. You shouldn't need to do anything by default, unless you need
	 * password grants, in which case you need to provide an {@link AuthenticationManager}.
	 * 
	 * @param endpoints the endpoints configurer
	 */
	void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception;

 

AuthorizationServerEndpointsConfigurer Core methoh

1.Create default DefaultTokenServices

private DefaultTokenServices createDefaultTokenServices() {
		DefaultTokenServices tokenServices = new DefaultTokenServices();
		tokenServices.setTokenStore(tokenStore());
		tokenServices.setSupportRefreshToken(true);
		tokenServices.setReuseRefreshToken(reuseRefreshToken);
		tokenServices.setClientDetailsService(clientDetailsService());
		tokenServices.setTokenEnhancer(tokenEnhancer());
		addUserDetailsService(tokenServices, this.userDetailsService);
		return tokenServices;
	}

2.clientDetailsService

private ClientDetailsService clientDetailsService() {
		if (clientDetailsService == null) {
			this.clientDetailsService = new InMemoryClientDetailsService();
		}
		if (this.defaultTokenServices != null) {
			addUserDetailsService(defaultTokenServices, userDetailsService);
		}
		return this.clientDetailsService;
	}

ClientDetailsService默認是InMemoryClientDetailsService。

3.TokenStore

private TokenStore tokenStore() {
		if (tokenStore == null) {
			if (accessTokenConverter() instanceof JwtAccessTokenConverter) {
				this.tokenStore = new JwtTokenStore((JwtAccessTokenConverter) accessTokenConverter());
			}
			else {
				this.tokenStore = new InMemoryTokenStore();
			}
		}
		return this.tokenStore;
	}

  受權服務器啓動的時候,會調用AuthorizationServerEndpointsConfigurer.getDefaultAuthorizationServerTokenServices方法。

AuthorizationServerEndpointsConfiguration.defaultAuthorizationServerTokenServices會在啓動時進行初始化爲Bean,初始化默認的defaultAuthorizationServerTokenServices。

AuthorizationServerEndpointsConfigurer.defaultAuthorizationServerTokenServices

/**
	 * This needs to be a <code>@Bean</code> so that it can be
	 * <code>@Transactional</code> (in case the token store supports them). If
	 * you are overriding the token services in an
	 * {@link AuthorizationServerConfigurer} consider making it a
	 * <code>@Bean</code> for the same reason (assuming you need transactions,
	 * e.g. for a JDBC token store).
	 * 
	 * @return an AuthorizationServerTokenServices
	 */
	@Bean
	public AuthorizationServerTokenServices defaultAuthorizationServerTokenServices() {
		return endpoints.getDefaultAuthorizationServerTokenServices();
	}

 

AuthorizationServerEndpointsConfiguration The core initialization

 Initialize authorizationEndpoint and TokenEndpint.

@Bean
	public AuthorizationEndpoint authorizationEndpoint() throws Exception {
		AuthorizationEndpoint authorizationEndpoint = new AuthorizationEndpoint();
		FrameworkEndpointHandlerMapping mapping = getEndpointsConfigurer().getFrameworkEndpointHandlerMapping();
		authorizationEndpoint.setUserApprovalPage(extractPath(mapping, "/oauth/confirm_access"));
		authorizationEndpoint.setProviderExceptionHandler(exceptionTranslator());
		authorizationEndpoint.setErrorPage(extractPath(mapping, "/oauth/error"));
		authorizationEndpoint.setTokenGranter(tokenGranter());
		authorizationEndpoint.setClientDetailsService(clientDetailsService);
		authorizationEndpoint.setAuthorizationCodeServices(authorizationCodeServices());
		authorizationEndpoint.setOAuth2RequestFactory(oauth2RequestFactory());
		authorizationEndpoint.setOAuth2RequestValidator(oauth2RequestValidator());
		authorizationEndpoint.setUserApprovalHandler(userApprovalHandler());
		return authorizationEndpoint;
	}

	@Bean
	public TokenEndpoint tokenEndpoint() throws Exception {
		TokenEndpoint tokenEndpoint = new TokenEndpoint();
		tokenEndpoint.setClientDetailsService(clientDetailsService);
		tokenEndpoint.setProviderExceptionHandler(exceptionTranslator());
		tokenEndpoint.setTokenGranter(tokenGranter());
		tokenEndpoint.setOAuth2RequestFactory(oauth2RequestFactory());
		tokenEndpoint.setOAuth2RequestValidator(oauth2RequestValidator());
		tokenEndpoint.setAllowedRequestMethods(allowedTokenEndpointRequestMethods());
		return tokenEndpoint;
	}

	@Bean
	public CheckTokenEndpoint checkTokenEndpoint() {
		CheckTokenEndpoint endpoint = new CheckTokenEndpoint(getEndpointsConfigurer().getResourceServerTokenServices());
		endpoint.setAccessTokenConverter(getEndpointsConfigurer().getAccessTokenConverter());
		endpoint.setExceptionTranslator(exceptionTranslator());
		return endpoint;
	}

	@Bean
	public WhitelabelApprovalEndpoint whitelabelApprovalEndpoint() {
		return new WhitelabelApprovalEndpoint();
	}

	@Bean
	public WhitelabelErrorEndpoint whitelabelErrorEndpoint() {
		return new WhitelabelErrorEndpoint();
	}

	@Bean
	public FrameworkEndpointHandlerMapping oauth2EndpointHandlerMapping() throws Exception {
		return getEndpointsConfigurer().getFrameworkEndpointHandlerMapping();
	}

	@Bean
	public ConsumerTokenServices consumerTokenServices() throws Exception {
		return getEndpointsConfigurer().getConsumerTokenServices();
	}

	/**
	 * This needs to be a <code>@Bean</code> so that it can be
	 * <code>@Transactional</code> (in case the token store supports them). If
	 * you are overriding the token services in an
	 * {@link AuthorizationServerConfigurer} consider making it a
	 * <code>@Bean</code> for the same reason (assuming you need transactions,
	 * e.g. for a JDBC token store).
	 * 
	 * @return an AuthorizationServerTokenServices
	 */
	@Bean
	public AuthorizationServerTokenServices defaultAuthorizationServerTokenServices() {
		return endpoints.getDefaultAuthorizationServerTokenServices();
	}

	public AuthorizationServerEndpointsConfigurer getEndpointsConfigurer() {
		if (!endpoints.isTokenServicesOverride()) {
			endpoints.tokenServices(defaultAuthorizationServerTokenServices());
		}
		return endpoints;
	}

  其中comsumerTokenService() and defaultAuthorizationServerTokenServices()都將調用AuthorizationServerEndpointsConfigurer的createDefaultTokenServices方法兩次,前一個方法初始化consumerTokenServices,後一個方法初始化defaultTokenServices。

ConsumerTokenServices and AuthorizationServerTokenServices are interfaces。DefaultTokenServices類同時實現ConsumerTokenServices和AuthorizationServerTokenServices。

 

AuthorizationServerSecurityConfiguration

AuthorizationServerSecurityConfiguration statement is as follows:

@Configuration
@Order(0)
@Import({ ClientDetailsServiceConfiguration.class, AuthorizationServerEndpointsConfiguration.class })
public class AuthorizationServerSecurityConfiguration extends WebSecurityConfigurerAdapter {
  ...
}

Import ClientDetailsServiceConfiguration

  客戶端憑證配置類。初始化客戶端憑證數據,由內存初始化,或者來自jdbc。

@Configuration
public class ClientDetailsServiceConfiguration {

	@SuppressWarnings("rawtypes")
	private ClientDetailsServiceConfigurer configurer = new ClientDetailsServiceConfigurer(new ClientDetailsServiceBuilder());
	
	@Bean
	public ClientDetailsServiceConfigurer clientDetailsServiceConfigurer() {
		return configurer;
	}

	@Bean
	@Lazy
	@Scope(proxyMode=ScopedProxyMode.INTERFACES)
	public ClientDetailsService clientDetailsService() throws Exception {
		return configurer.and().build();
	}

}

Default ClientDetailsService是在ClientDetailsServiceConfiguration類中生成的。由以下方法

@Bean
	@Lazy
	@Scope(proxyMode=ScopedProxyMode.INTERFACES)
	public ClientDetailsService clientDetailsService() throws Exception {
		return configurer.and().build();
	}

 

Import AuthorizationServerEndpointsConfiguration

受權服務器端點配置類,在@EnableAuthorizationServer中也引入了AuthorizationServerEndpointsConfiguration.class的配置。

 

UserDetailService

 The default userDetailService是在WebSecurityConfigurerAdapter中初始化。

userDetailService是加載用戶特定數據的核心接口,至關於用戶DAO,是該策略。

org.springframework.security.authentication.dao.DaoAuthenticationProvider

* DaoAuthenticationProvider

該接口只有一個只讀方法,用於數據訪問。

UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;

默認實現是UserDetailsServiceDelegator,該類屬於static final class。

聲明於WebSecurityConfigurerAdapter.UserDetailsServiceDelegator。

 

 

AuthorizationServerSecurityConfiguration 此類也extends自WebSecurityConfigurerAdapter 。

但通常咱們本身也會聲明一個類來extends此類WebSecurityConfigurerAdapter 。

相關文章
相關標籤/搜索