问题描述
我正在学习有关 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 登录页面会告诉我:
如果我点击第一个选项,它会将我重定向到一个我只能更新我的基本信息的页面,当我点击提交时,它会再次将我重定向到同一页面:
如果我点击第二个选项,它会再次将我重定向到第一页。由于我没有密码,我无法以传统方式登录。
剩下的唯一选择是谷歌,我观察到为了将现有的谷歌帐户与 Facebook 链接(反之亦然),我必须登录初始社交提供商。然后我可以在登录会话之间很好地切换提供程序。但是我想跳过这一步,如果用户存在直接登录。
问题
如何绕过此帐户已存在消息并使其在已找到现有用户的情况下自动登录?同样,只有当我使用的社交提供商与我第一次登录时使用的社交提供商不同时,才会发生这种情况。
我想我必须覆盖浏览器流程中的一些配置,但我不知道到底需要更改什么。任何帮助表示赞赏。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)