引入
@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();
}
}