微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

无法在 Keycloak 中将 Google 帐户链接到 Facebook 帐户,反之亦然

如何解决无法在 Keycloak 中将 Google 帐户链接到 Facebook 帐户,反之亦然

我正在学习有关 OAuth2 和 Spring Security 的教程,并且我已经配置了一个简单的 Spring MVC 应用程序。登录部分被外部化为一个名为 Keycloak 的单独解决方案。在提出问题之前,我想提供一些背景信息,以便更好地理解我的问题。

上下文

在 Keycloak 内部,有一个名为 CryptoPortfolio 的领域和一个名为 crypto-portfolio 的客户端。客户端是机密,并且具有openid-connect 协议。我配置了两个指向 Spring 应用程序的重定向链接: http://localhost:8080/login/oauth2/code/crypto-portfolio - 用于登录
http://localhost:8080/ - 用于注销

本地 Keycloak 和本地应用程序之间的链接是通过 application.yaml 文件建立的:

security:
    oauth2:
      client:
        registration:
          crypto-portfolio:
            client-id: crypto-portfolio
            client-secret: 25990e05-e846-41c0-9159-ce2a10a78102
            client-name: Crypto Portoflio
            redirect-uri: http://localhost:8080/login/oauth2/code/crypto-portfolio
            authorization-grant-type: authorization_code
            scope: openid
            provider: keycloak
        provider:
          keycloak:
            issuer-uri: http://localhost:8081/auth/realms/CryptoPortfolio

扩展WebSecurityConfigurerAdapter的配置类非常简单:

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    private final AuthenticationSuccessHandlerImpl authenticationSuccessHandler;
    private final ClientRegistrationRepository clientRegistrationRepository;

    public SecurityConfiguration(AuthenticationSuccessHandlerImpl authenticationSuccessHandler,ClientRegistrationRepository clientRegistrationRepository) {
        this.authenticationSuccessHandler = authenticationSuccessHandler;
        this.clientRegistrationRepository = clientRegistrationRepository;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated();

        http.oauth2Login()
                // the login redirect link configured as OAuth2AuthorizationRequestRedirectFilter expects it
                .loginPage("/oauth2/authorization/crypto-portfolio")
                .successHandler(authenticationSuccessHandler)
                .and()
                .logout()
                .logoutSuccessHandler(oidclogoutSuccessHandler());
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/css/**","/webjars/**");
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

    private OidcclientinitiatedlogoutSuccessHandler oidclogoutSuccessHandler() {
        final OidcclientinitiatedlogoutSuccessHandler logoutHandler =
                new OidcclientinitiatedlogoutSuccessHandler(clientRegistrationRepository);
        logoutHandler.setPostlogoutRedirectUri("http://localhost:8080/");
        return logoutHandler;
    }
}

如果新用户不存在,身份验证成功处理程序会创建一个新用户并发送重定向到根页面

@Component
public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler {

    private final PortfolioQueryService portfolioQueryService;
    private final UserRegistrationService userRegistrationService;

    public AuthenticationSuccessHandlerImpl(PortfolioQueryService portfolioQueryService,UserRegistrationService userRegistrationService) {
        this.portfolioQueryService = portfolioQueryService;
        this.userRegistrationService = userRegistrationService;
    }

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,HttpServletResponse response,Authentication authentication) throws IOException,servletexception {
        if (portfolioQueryService.getPortfolioPositions(authentication.getName()).isEmpty()) {
            OidcUser principal = (OidcUser) authentication.getPrincipal();

            UserRegistrationRequest userRegistrationRequest = new UserRegistrationRequest();
            userRegistrationRequest.setFirstName(principal.getGivenname());
            userRegistrationRequest.setLastName(principal.getFamilyName());
            userRegistrationRequest.setEmail(principal.getEmail());
            userRegistrationRequest.setUsername(principal.getSubject());
            userRegistrationService.registerNewUser(userRegistrationRequest);
        }

        response.sendRedirect("/portfolio");
    }

我已经配置了两个提供商,Facebook 和 Google,并在 Keycloack 中填写了他们的客户端 ID 和机密。我已将重定向 URI 添加到 Google 内部的 Keycloack:http://localhost:8081/auth/realms/CryptoPortfolio/broker/google/endpoint 和 Facebook,我还没有这样做,因为它会自动接受所有本地主机端点.

问题

我成功登录 Facebook,创建了一个新用户。我也可以退出并重新登录 Facebook。但是,如果我使用 Facebook 登录并尝试使用其他社交帐户(例如 Google)登录,Keycloak 登录页面会告诉我:

Account already exists

如果我点击第一个选项,它会将我重定向一个我只能更新我的基本信息的页面,当我点击提交时,它会再次将我重定向到同一页面

Review Profile

如果我点击第二个选项,它会再次将我重定向到第一页。由于我没有密码,我无法以传统方式登录

Add to existing account

剩下的唯一选择是谷歌,我观察到为了将现有的谷歌帐户与 Facebook 链接(反之亦然),我必须登录初始社交提供商。然后我可以在登录会话之间很好地切换提供程序。但是我想跳过这一步,如果用户存在直接登录

问题

如何绕过此帐户已存在消息并使其在已找到现有用户的情况下自动登录?同样,只有当我使用的社交提供商与我第一次登录时使用的社交提供商不同时,才会发生这种情况。

我想我必须覆盖浏览器流程中的一些配置,但我不知道到底需要更改什么。任何帮助表示赞赏。

Browser Flow

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。