使用Spring Social进行二次Facebook登录

2023/05/17

1. 概述

在本教程中,我们将专注于将新的 Facebook 登录添加到现有的表单登录应用程序。

我们将使用 Spring Social 支持与 Facebook 交互并保持简洁明了。

2.Maven配置

首先,我们需要将spring-social-facebook依赖添加到我们的pom.xml中:

<dependency>
    <groupId>org.springframework.social</groupId>
    <artifactId>spring-social-facebook</artifactId>
    <version>2.0.3.RELEASE</version>
</dependency>

3. 安全配置——只需表单登录

让我们首先从简单的安全配置开始,其中我们只有基于表单的身份验证:

@Configuration
@EnableWebSecurity
@ComponentScan(basePackages = { "com.baeldung.security" })
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) 
      throws Exception {
        auth.userDetailsService(userDetailsService);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
        .csrf().disable()
        .authorizeRequests()
        .antMatchers("/login").permitAll()
        .anyRequest().authenticated()
        .and()
        .formLogin().loginPage("/login").permitAll();
    } 
}

我们不会在这个配置上花费太多时间——如果想更好地理解它,请查看表单登录文章

4. Facebook 属性

接下来,让我们在application.properties中配置 Facebook 属性:

spring.social.facebook.appId=YOUR_APP_ID
spring.social.facebook.appSecret=YOUR_APP_SECRET

注意:

  • 我们需要创建一个 Facebook 应用来获取appId和appSecret
  • 在 Facebook 应用程序设置中,确保添加平台“网站”并且http://localhost:8080/是“站点 URL”

5. 安全配置 - 添加 Facebook

现在,让我们在系统中添加一种新的身份验证方式——由 Facebook 驱动:

public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private FacebookConnectionSignup facebookConnectionSignup;

    @Value("${spring.social.facebook.appSecret}")
    String appSecret;
    
    @Value("${spring.social.facebook.appId}")
    String appId;
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
        .authorizeRequests()
        .antMatchers("/login","/signin/","/signup/").permitAll()
        ...
    } 

    @Bean
    public ProviderSignInController providerSignInController() {
        ConnectionFactoryLocator connectionFactoryLocator = 
            connectionFactoryLocator();
        UsersConnectionRepository usersConnectionRepository = 
            getUsersConnectionRepository(connectionFactoryLocator);
        ((InMemoryUsersConnectionRepository) usersConnectionRepository)
            .setConnectionSignUp(facebookConnectionSignup);
        return new ProviderSignInController(connectionFactoryLocator, 
            usersConnectionRepository, new FacebookSignInAdapter());
    }
    
    private ConnectionFactoryLocator connectionFactoryLocator() {
        ConnectionFactoryRegistry registry = new ConnectionFactoryRegistry();
        registry.addConnectionFactory(new FacebookConnectionFactory(appId, appSecret));
        return registry;
    }
    
    private UsersConnectionRepository getUsersConnectionRepository(ConnectionFactoryLocator 
        connectionFactoryLocator) {
        return new InMemoryUsersConnectionRepository(connectionFactoryLocator);
    }
}

让我们仔细看看新的配置:

  • 我们使用 ProviderSignInController 来启用 Facebook 身份验证,这需要两件事: 首先,使用 我们之前定义的 Facebook 属性 注册为 FacebookConnectionFactory的ConnectionFactoryLocator 。 第二,一个 InMemoryUsersConnectionRepository。
  • 通过向“ /signin/facebook ”发送POST ——该控制器将使用 Facebook 服务提供商启动用户登录
  • 我们正在设置一个SignInAdapter来处理我们应用程序中的登录逻辑
  • 我们还设置了ConnectionSignUp以在用户首次使用 Facebook 进行身份验证时隐式处理注册用户

6.登录适配器

简单地说,这个适配器是上面的控制器(驱动 Facebook 用户登录流程)和我们特定的本地应用程序之间的桥梁:

public class FacebookSignInAdapter implements SignInAdapter {
    @Override
    public String signIn(
      String localUserId, 
      Connection<?> connection, 
      NativeWebRequest request) {
        
        SecurityContextHolder.getContext().setAuthentication(
          new UsernamePasswordAuthenticationToken(
          connection.getDisplayName(), null, 
          Arrays.asList(new SimpleGrantedAuthority("FACEBOOK_USER"))));
        
        return null;
    }
}

请注意,使用 Facebook 登录的用户将拥有FACEBOOK_USER角色,而使用表单登录的用户将拥有USER 角色。

7.连接注册

当用户第一次使用 Facebook 进行身份验证时,他们在我们的应用程序中没有现有帐户。

这就是我们需要为他们自动创建该帐户的地方;我们将使用ConnectionSignUp来驱动该用户创建逻辑:

@Service
public class FacebookConnectionSignup implements ConnectionSignUp {

    @Autowired
    private UserRepository userRepository;

    @Override
    public String execute(Connection<?> connection) {
        User user = new User();
        user.setUsername(connection.getDisplayName());
        user.setPassword(randomAlphabetic(8));
        userRepository.save(user);
        return user.getUsername();
    }
}

如所见,我们为新用户创建了一个帐户——使用他们的DisplayName作为用户名。

8. 前端

最后,让我们看看我们的前端。

我们现在将在我们的登录页面上支持这两个身份验证流程——表单登录和 Facebook:

<html>
<body>
<div th:if="${param.logout}">You have been logged out</div>
<div th:if="${param.error}">There was an error, please try again</div>

<form th:action="@{/login}" method="POST" >
    <input type="text" name="username" />
    <input type="password" name="password" />
    <input type="submit" value="Login" />
</form>
	
<form action="/signin/facebook" method="POST">
    <input type="hidden" name="scope" value="public_profile" />
    <input type="submit" value="Login using Facebook"/>
</form>
</body>
</html>

最后——这里是index.html:

<html>
<body>
<nav>
    <p sec:authentication="name">Username</p>      
    <a th:href="@{/logout}">Logout</a>                     
</nav>

<h1>Welcome, <span sec:authentication="name">Username</span></h1>
<p sec:authentication="authorities">User authorities</p>
</body>
</html>

请注意此索引页面如何显示用户名和权限。

就是这样——我们现在有两种方法可以在应用程序中进行身份验证。

9. 总结

在这篇快速文章中,我们学习了如何使用spring-social-facebook为我们的应用程序实现二级身份验证流程。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章