场景
SecurityContext
并已登录的用户登录此帐户。我的安全配置为:
@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.requiresChannel()
.anyRequest().requiresSecure()
.and()
.headers()
.frameOptions()
.sameOrigin()
.and()
.antMatcher("/**")
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/register", "/login").permitAll()
.antMatchers("/static/**", "/css/**", "/js/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/?login")
.loginProcessingUrl("/login")
.failureUrl("/?error")
.passwordParameter("password")
.usernameParameter("emailAddress")
.successHandler(authenticationSuccessHandler())
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/")
.and()
.oauth2Login()
.loginPage("/?login")
.failureUrl("/?error")
.successHandler(authenticationSuccessHandler())
.and()
.httpBasic();
}
}
我的应用程序属性是:
spring:
security:
oauth2:
client:
registration:
google:
clientId: <removed>
clientSecret: <removed>
facebook:
clientId: <removed>
clientSecret: <removed>
provider:
facebook:
userInfoUri: https://graph.facebook.com/me?fields=id,email,first_name
我尝试了什么
我的第一个想法是将另一个社交登录按钮添加到“通过身份验证的用户”屏幕上(注意:这与登录按钮相同)。这样可以正确地将它们重定向到OAuth2提供程序,然后登录,然后将它们重定向回到应用程序。问题是因为这会经过“ OAuth2登录”的常规过滤过程,因此会将SecurityContext
切换为现在具有新的OAuth2凭据,从而丢失了以前登录的用户。
发生这种情况是因为OAuth2LoginAuthenticationFilter
扩展了AbstractAuthenticationProcessingFilter
,并且在方法successfulAuthentication
中它清除了安全上下文并插入了新的凭据:
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Authentication success. Updating SecurityContextHolder to contain: " + authResult);
}
SecurityContextHolder.getContext().setAuthentication(authResult);
this.rememberMeServices.loginSuccess(request, response, authResult);
if (this.eventPublisher != null) {
this.eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
}
this.successHandler.onAuthenticationSuccess(request, response, authResult);
}
所以我想嘿!为什么不重写OAuth2LoginAuthenticationFilter
,然后实现我自己的successfulAuthentication
,它可以检测我们是否已经登录了另一个用户。如果没有,请执行正常的行为。如果我们确实获得了该用户,请在他们身上弹出OAuth2提供程序提供给我们的唯一ID,然后继续过滤链。 重要不更改SecurityContext
。
事实并非如此简单,因为使用了OAuth2LoginConfigurer
的{{1}}硬编码,并且您无法提供要使用的其他编码:
OAuth2LoginAuthenticationFilter
并且public void init(B http) throws Exception {
OAuth2LoginAuthenticationFilter authenticationFilter = new OAuth2LoginAuthenticationFilter(this.getClientRegistrationRepository(), this.getAuthorizedClientService(), this.loginProcessingUrl);
this.setAuthenticationFilter(authenticationFilter);
...
}
方法不是公开的:
setAuthenticationFilter
如果他们愿意,我还想取消用户与OAuth2登录名的链接,除了只是删除他们在数据库中指向该唯一ID的链接之外,我还应该怎么做?
正在使用的版本
Spring Boot:2.0.5.RELEASE
Spring Security:5.0.8.RELEASE
先谢谢您。如果需要,我很乐意提供更多信息。
注意 我不相信这已经被问过了。经过广泛的Google搜索后,所有文档似乎都在使用OAuth2登录名登录该应用程序,并且该帐户与另一个OAuth2登录名没有关联。