使用 Spring Security 在表单登录和 OAuth2 登录之间进行选择

Posted

技术标签:

【中文标题】使用 Spring Security 在表单登录和 OAuth2 登录之间进行选择【英文标题】:Choice between form login and OAuth2 login with Spring Security 【发布时间】:2020-08-11 04:03:29 【问题描述】:

我想实现一个简单的应用程序,使用户能够使用本地帐户登录或注册新帐户或使用 OAuth2 登录 - 例如Facebook。对于选择 Facebook 的用户,我想自动创建一个本地帐户并使用该帐户登录。

据我了解Spring Social 是dead(如果在项目主页上提到这将非常有帮助,因为它会为像我这样投资学习spring social 的人节省努力)。

我理解的另一件事是“OAuth2 和 OIDC 现在是 Spring Boot 和 Spring Security 生态系统中的一等公民”。似乎正确的方法是使用 Spring Security 5 及其对 OAuth2 的一流支持!

那么……我们走吧。我的application.yaml

spring:
  security:
    oauth2:
      client:
        registration:
          facebook:
            client-id: senko
            client-secret: topsecret

安全配置:

  @Override
  protected void configure(HttpSecurity http) throws Exception 

    // for the ant pattern matcher syntax, please check:
    // https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/util/AntPathMatcher.html

    http
        .formLogin()
          .loginPage("/login")
          .loginProcessingUrl("/login/authenticate")
          .failureUrl("/login?param.error=bad_credentials")
          .successForwardUrl("/home")
        .and()
          .logout()
          .logoutUrl("/logout")
          .deleteCookies("JSESSIONID").
        and()
          .authorizeRequests()
          .antMatchers("/login**").permitAll()
          .antMatchers("/**").authenticated().
        and().
          oauth2Login().
          loginPage("/login");
  

  @Override
  public void configureGlobal(AuthenticationManagerBuilder auth)
    throws Exception 
      auth.userDetailsService(userDetailsService).passwordEncoder(
      new BCryptPasswordEncoder());
  

我的用户服务使用 mysql 支持的本地存储。登录表单简称(thymeleaf):

Login:

<form id="signin" th:action="@/login/authenticate" method="post">
      <input id="login" name="username" type="text" size="25"></input>
      <input id="password" name="password" type="password" size="25"></input>
      <button type="submit">Login In</button>
</form>

Or...:
<a th:href="@/oauth2/authorization/facebook">Sign in with Facebook</a>

到目前为止,我可以使用本地帐户登录。我也可以使用 Facebook 登录。我在这里错过的是成功登录 Facebook 后我应该创建本地用户帐户的部分。实现它的正确方法是什么?我完全一无所知。到目前为止,我尝试的是在谷歌中搜索并阅读OAuth2LoginAuthenticationProvider 的代码。任何帮助将不胜感激。

更新:我正在探索实施 AuthenticationSuccessHandler 是否是一个合适的选择...

【问题讨论】:

当你写你想创建一个本地用户帐户时,你的意思是什么?您想在您的数据库中保留您在身份验证期间从 Facebook 获得的用户详细信息吗? 是的。目前我正在 AuthenticationSuccessHandler 中这样做。 @LachezarBalev 你找到解决方案了吗? 【参考方案1】:

您可以注册一个自定义 bean (OAuth2UserService),它将自动替换默认配置。实际上,下面的示例只是从默认配置委托给一个实现,但允许扩展/添加其他逻辑(在此示例中处理用户)。

@Bean
public OAuth2UserService<OAuth2UserRequest, OAuth2User> oauth2UserService() 
    
    DefaultOAuth2UserService service = new DefaultOAuth2UserService();
    return request -> 
        OAuth2User user = service.loadUser(request);
        
        System.out.println("User attributes: " + user.getAttributes()); // can be converted and saved
        
        return user;
    ;

【讨论】:

以上是关于使用 Spring Security 在表单登录和 OAuth2 登录之间进行选择的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Spring 获取之前捕获 Spring Security 登录表单?

使用 oAuth2.0 和表单登录的 Spring Security

如何在 grails 和现有 oauth2 提供程序中使用 Spring Security 实现基于表单的登录

如何配置 Spring Boot 和 Spring Security 以支持表单登录和 Google OAuth2 登录

如何使用 Spring Security 3.1.3 和 JSF 创建一个 Bean 来验证我的登录表单

是否可以使用jsp登录表单作为spring security的自定义登录表单