@EnableOAuth2Sso
注解详情
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@EnableOAuth2Client
@EnableConfigurationProperties({OAuth2SsoProperties.class}) // [1]
@Import({OAuth2SsoDefaultConfiguration.class, OAuth2SsoCustomConfiguration.class, ResourceServerTokenServicesConfiguration.class})
public @interface EnableOAuth2Sso {
}
由源码知@EnableOAuth2Sso是一个组合注解。
@EnableOAuth2Client
@EnableOAuth2Client
通过@Import导入了OAuth2ClientConfiguration
类。
OAuth2ClientConfiguration
类中注入了3个Bean:OAuth2ClientContextFilter
,AccessTokenRequest
和OAuth2ClientContextConfiguration
。
OAuth2ClientContextFilter
加入到过滤器链中,当后续的认证抛出UserRedirectRequiredException
异常时,会重定向。。。「后续补充」
@EnableConfigurationProperties
@EnableConfigurationProperties
启用OAuth2SsoProperties
配置类。
security.oauth2.sso.loginPath=/login
@Import
导入了OAuth2SsoDefaultConfiguration
,OAuth2SsoCustomConfiguration
和ResourceServerTokenServicesConfiguration
三个配置类。
看OAuth2SsoDefaultConfiguration的条件@Conditional({OAuth2SsoDefaultConfiguration.NeedsWebSecurityCondition.class})和OAuth2SsoCustomConfiguration上的条件@Conditional({EnableOAuth2SsoCondition.class}),它们两个是取反的逻辑,即只能有一个生效。
@Conditional({EnableOAuth2SsoCondition.class})是指当项目中有WebSecurityConfigurerAdapter.class的Bean时为真,即项目中继承了WebSecurityConfigurerAdapter抽象类。
OAuth2SsoDefaultConfiguration继承了WebSecurityConfigurerAdapter,重写了config(HttpSecurity)方法
OAuth2SsoDefaultConfiguration#configure
protected void configure(HttpSecurity http) throws Exception {
((AuthorizedUrl)http.antMatcher("/**").authorizeRequests().anyRequest()).authenticated();
(new SsoSecurityConfigurer(this.applicationContext)).configure(http);
}
方法中配置了所有的请求都需要认证后访问。另外,调用了SsoSecurityConfigurer的config方法。
SsoSecurityConfigurer#configure
public void configure(HttpSecurity http) throws Exception {
// 在[1]处已经启用了OAuth2SsoProperties属性类
OAuth2SsoProperties sso = (OAuth2SsoProperties)this.applicationContext.getBean(OAuth2SsoProperties.class);
// oauth2SsoFilter方法返回OAuth2ClientAuthenticationProcessingFilter对象
// OAuth2ClientAuthenticationConfigurer主要作用将OAuth2ClientAuthenticationProcessingFilter添加到过滤器链中
http.apply(new SsoSecurityConfigurer.OAuth2ClientAuthenticationConfigurer(this.oauth2SsoFilter(sso)));
// 认证失败的异常处理端点
this.addAuthenticationEntryPoint(http, sso);
}
SsoSecurityConfigurer#oauth2SsoFilter
private OAuth2ClientAuthenticationProcessingFilter oauth2SsoFilter(OAuth2SsoProperties sso) {
OAuth2RestOperations restTemplate = ((UserInfoRestTemplateFactory)this.applicationContext.getBean(UserInfoRestTemplateFactory.class)).getUserInfoRestTemplate();
ResourceServerTokenServices tokenServices = (ResourceServerTokenServices)this.applicationContext.getBean(ResourceServerTokenServices.class);
OAuth2ClientAuthenticationProcessingFilter filter = new OAuth2ClientAuthenticationProcessingFilter(sso.getLoginPath());
filter.setRestTemplate(restTemplate);
filter.setTokenServices(tokenServices);
filter.setApplicationEventPublisher(this.applicationContext);
return filter;
}
方法返回OAuth2ClientAuthenticationProcessingFilter对象,OAuth2ClientAuthenticationProcessingFilter与UsernamePasswordAuthenticationFilter一样处理用户认证的逻辑。不同的是UsernamePasswordAuthenticationFilter通过username和password去认证了,而OAuth2ClientAuthenticationProcessingFilter是通过OAuth2RestOperations「restTemplate」取获取accessToken,然后使用accessToken获取认证信息。
SsoSecurityConfigurer.OAuth2ClientAuthenticationConfigurer类
private static class OAuth2ClientAuthenticationConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
private OAuth2ClientAuthenticationProcessingFilter filter;
OAuth2ClientAuthenticationConfigurer(OAuth2ClientAuthenticationProcessingFilter filter) {
this.filter = filter;
}
public void configure(HttpSecurity builder) throws Exception {
OAuth2ClientAuthenticationProcessingFilter ssoFilter = this.filter;
ssoFilter.setSessionAuthenticationStrategy((SessionAuthenticationStrategy)builder.getSharedObject(SessionAuthenticationStrategy.class));
// 将OAuth2ClientAuthenticationProcessingFilter添加到过滤器链中
builder.addFilterAfter(ssoFilter, AbstractPreAuthenticatedProcessingFilter.class);
}
}
该类的config方法中为OAuth2ClientAuthenticationProcessingFilter设置了Session策略,然后将其添加到过滤器链中。
该类OAuth2SsoCustomConfiguration作用是:如果项目中实现了WebSecurityConfigurerAdapter的配置类,则为该类使用代理。
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 OAuth2SsoCustomConfiguration.SsoSecurityAdapter(this.applicationContext));
bean = factory.getProxy();
}
return bean;
}
SsoSecurityAdapter
private static class SsoSecurityAdapter implements MethodInterceptor {
private SsoSecurityConfigurer configurer;
SsoSecurityAdapter(ApplicationContext applicationContext) {
this.configurer = new SsoSecurityConfigurer(applicationContext);
}
public Object invoke(MethodInvocation invocation) throws Throwable {
if (invocation.getMethod().getName().equals("init")) {
// 在调用init方法添加SsoSecurityConfigurer配置类
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();
}
}
这个配置类主要是向容器中添加了UserInfoRestTemplateFactory和JwtToken相关的配置,被用于获取用户信息及token的生成与存储。