文档章节

Spring Security OAuth2 Source code analysis

Nathans
 Nathans
发布于 2017/03/22 15:27
字数 2164
阅读 235
收藏 0

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

OAuth 2.0 Provider Implementation

@EnableAuthorizationServer Annotation

The @EnableAuthorizationServer statement is as follows:

/**
 * 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的类。

  通过一个或多个AuthprizationServerConfigurers提供一个ClientDetailService来注册客户端。

该注解同时会启用AuthorizationEndpoint和TokenEndpoint,并且需要在DispatcherServlet上下文。

AuthorizationServerConfigurer

The @AuthorizationServerConfigurer statement is as follows:

/**
 * 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接口,提供空实现。

TheAuthorizationServerConfigurerAdapter statement is as follows:

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。

OAuth2AuthprizationServerConfiguration

  OAuth2AuthprizationServerConfiguration statement is as follows:

/**
 * 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 。

© 著作权归作者所有

Nathans
粉丝 6
博文 18
码字总数 28409
作品 0
成都
程序员
私信 提问
Spring Security OAuth 2.0.12 发布,Bug 修复

Spring Security OAuth 2.0.12 发布了,该版本未发现重大更新,更新内容主要包括错误修复和一些次要的增强。查看提交记录了解更多。 查看发布说明 下载地址: Source code (zip) Source cod...

局长
2016/11/08
1K
1
Spring Security Oauth 2.3.2 发布

spring-security-oauth 2.3.2 发布,目前暂未发现更新信息,您可查看发布主页保持关注。 Spring Security OAuth 是 Spring Security 的 OAuth 插件,同时提供了 OAuth 客户端(consumer)和服务...

淡漠悠然
2018/04/12
523
0
Spring Security Oauth 2.3.1 发布

spring-security-oauth 2.3.1 发布,目前暂未发现更新信息,您可查看发布主页保持关注。 Spring Security OAuth 是 Spring Security 的 OAuth 插件,同时提供了 OAuth 客户端(consumer)和服务...

淡漠悠然
2018/04/11
1K
0
Spring Security OAuth 2.3.0 发布,新增签名验证

Spring Security OAuth 2.3.0 已发布,Spring Security OAuth 是 Spring Security 的 OAuth 插件,同时提供了 OAuth 客户端(consumer)和服务器端(provider)的实现,支持 OAuth1(a) 和 OAuth2......

周其
2018/03/17
1K
7
Spring Boot 1.4.7 发布

Spring Boot 1.4.7 发布了,该版本包含 30 多项更改,主要是依赖性升级和文档改进。部分如下: Update to Spring Integration 4.3.10 Upgrade to Spring Framework 4.3.9.RELEASE Upgrade to...

淡漠悠然
2017/06/08
1K
5

没有更多内容

加载失败,请刷新页面

加载更多

总结

一、设计模式 简单工厂:一个简单而且比较杂的工厂,可以创建任何对象给你 复杂工厂:先创建一种基础类型的工厂接口,然后各自集成实现这个接口,但是每个工厂都是这个基础类的扩展分类,spr...

BobwithB
34分钟前
3
0
java内存模型

前言 Java作为一种面向对象的,跨平台语言,其对象、内存等一直是比较难的知识点。而且很多概念的名称看起来又那么相似,很多人会傻傻分不清楚。比如本文我们要讨论的JVM内存结构、Java内存模...

ls_cherish
37分钟前
3
0
友元函数强制转换

友元函数强制转换 p522

天王盖地虎626
昨天
5
0
js中实现页面跳转(返回前一页、后一页)

本文转载于:专业的前端网站➸js中实现页面跳转(返回前一页、后一页) 一:JS 重载页面,本地刷新,返回上一页 复制代码代码如下: <a href="javascript:history.go(-1)">返回上一页</a> <a h...

前端老手
昨天
5
0
JAVA 利用时间戳来判断TOKEN是否过期

import java.time.Instant;import java.time.LocalDateTime;import java.time.ZoneId;import java.time.ZoneOffset;import java.time.format.DateTimeFormatter;/** * @descri......

huangkejie
昨天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部