天天看點

Spring Security OAuth2源碼解析(三)——單點登入。引入

引入

@EnableOAuth2Client
@EnableConfigurationProperties(OAuth2SsoProperties.class)
@Import({ OAuth2SsoDefaultConfiguration.class, OAuth2SsoCustomConfiguration.class,
		ResourceServerTokenServicesConfiguration.class })
public @interface EnableOAuth2Sso {

}
           

EnableOAuth2Sso注解引入了3個配置類:OAuth2SsoDefaultConfiguration,OAuth2SsoCustomConfiguration,ResourceServerTokenServicesConfiguration和一個屬性類OAuth2SsoProperties。

OAuth2SsoProperties 

OAuth2SsoProperties 主要用于設定單點登入login path。

@ConfigurationProperties(prefix = "security.oauth2.sso")
public class OAuth2SsoProperties {

	public static final String DEFAULT_LOGIN_PATH = "/login";
}
           

ResourceServerTokenServicesConfiguration

ResourceServerTokenServicesConfiguration用于引入資源服務,token服務的配置資訊。

OAuth2SsoDefaultConfiguration

OAuth2SsoDefaultConfiguration實作WebSecurityConfigurerAdapter。所有資源都需要驗證。

同時引入了配置SsoSecurityConfigurer。

@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.antMatcher("/**").authorizeRequests().anyRequest().authenticated();
		new SsoSecurityConfigurer(this.applicationContext).configure(http);
	}
           

 SsoSecurityConfigurer

SsoSecurityConfigurer引入了OAuth2ClientAuthenticationProcessingFilter 。

@Override
		public void configure(HttpSecurity builder) throws Exception {
			OAuth2ClientAuthenticationProcessingFilter ssoFilter = this.filter;
			ssoFilter.setSessionAuthenticationStrategy(builder.getSharedObject(SessionAuthenticationStrategy.class));
			builder.addFilterAfter(ssoFilter, AbstractPreAuthenticatedProcessingFilter.class);
		}
           

OAuth2ClientAuthenticationProcessingFilter

OAuth2ClientAuthenticationProcessingFilter過濾器 其要完成的工作就是 通過擷取到的code碼調用 授權服務 /oauth/token 接口擷取 token 資訊,并将擷取到的token 資訊解析成 OAuth2Authentication 認證對象。

@Override
	public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
			throws AuthenticationException, IOException, ServletException {

		OAuth2AccessToken accessToken;
		try {
			accessToken = restTemplate.getAccessToken();
		} catch (OAuth2Exception e) {
			BadCredentialsException bad = new BadCredentialsException("Could not obtain access token", e);
			publish(new OAuth2AuthenticationFailureEvent(bad));
			throw bad;			
		}
		try {
			OAuth2Authentication result = tokenServices.loadAuthentication(accessToken.getValue());
			if (authenticationDetailsSource!=null) {
				request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_VALUE, accessToken.getValue());
				request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_TYPE, accessToken.getTokenType());
				result.setDetails(authenticationDetailsSource.buildDetails(request));
			}
			publish(new AuthenticationSuccessEvent(result));
			return result;
		}
		catch (InvalidTokenException e) {
			BadCredentialsException bad = new BadCredentialsException("Could not obtain user details from token", e);
			publish(new OAuth2AuthenticationFailureEvent(bad));
			throw bad;			
		}

	}
           

OAuth2SsoCustomConfiguration

OAuth2SsoCustomConfiguration用于給ProxyFactory增加AOP

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		if (this.configType.isAssignableFrom(bean.getClass()) && bean instanceof WebSecurityConfigurerAdapter) {
			ProxyFactory factory = new ProxyFactory();
			factory.setTarget(bean);
			factory.addAdvice(new SsoSecurityAdapter(this.applicationContext));
			bean = factory.getProxy();
		}
		return bean;
	}
           
private static class SsoSecurityAdapter implements MethodInterceptor {

		private SsoSecurityConfigurer configurer;

		SsoSecurityAdapter(ApplicationContext applicationContext) {
			this.configurer = new SsoSecurityConfigurer(applicationContext);
		}

		@Override
		public Object invoke(MethodInvocation invocation) throws Throwable {
			if (invocation.getMethod().getName().equals("init")) {
				Method method = ReflectionUtils.findMethod(WebSecurityConfigurerAdapter.class, "getHttp");
				ReflectionUtils.makeAccessible(method);
				HttpSecurity http = (HttpSecurity) ReflectionUtils.invokeMethod(method, invocation.getThis());
				this.configurer.configure(http);
			}
			return invocation.proceed();
		}

	}
           

繼續閱讀