使用Spring Security与

时间:2018-10-12 10:24:57

标签: java spring-boot spring-security-oauth2

场景

  1. 我已经通过OAuth2登录在我的网站上创建了一个帐户。
  2. 我已登录SecurityContext并已登录的用户登录此帐户。
  3. 我希望将此帐户与其他OAuth2提供程序关联。
  4. 我希望取消此帐户与原始OAuth2提供商的关联。

我的安全配置为:

@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登录名没有关联。

0 个答案:

没有答案