Связать / отменить связь существующей учетной записи с поставщиком OAuth2 с помощью Spring Security - PullRequest
0 голосов
/ 12 октября 2018

Сценарий

  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, и продолжите цепочку фильтров. Важно не изменять SecurityContext.

Оказалось, что это не очень просто, поскольку жесткие коды OAuth2LoginConfigurer используют OAuth2LoginAuthenticationFilter, и вы не можете предоставить другой для использования:

public void init(B http) throws Exception {
    OAuth2LoginAuthenticationFilter authenticationFilter = new OAuth2LoginAuthenticationFilter(this.getClientRegistrationRepository(), this.getAuthorizedClientService(), this.loginProcessingUrl);
    this.setAuthenticationFilter(authenticationFilter);
    ...
}

И метод setAuthenticationFilter не является общедоступным:

protected final void setAuthenticationFilter(F authFilter) {
    this.authFilter = authFilter;
}

Я также хотел бы отсоединить пользователя от его логина OAuth2, если он пожелает, и помимо простого удаления егоссылка в базе данных на этот уникальный идентификатор, что еще для этого нужно сделать?

Используемые версии

Spring Boot: 2.0.5.RELEASE

Spring Security: 5.0.8. RELEASE

Заранее спасибо.Я рад предоставить больше информации, если это необходимо.

Примечание Я не верю, что об этом спрашивали раньше.После интенсивного поиска в Google вся документация, по-видимому, относится к входу в приложение с именем входа OAuth2, и ничто не связывает эту учетную запись с другим именем входа OAuth2.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...