A Secondary Facebook Login with Spring Social – 使用Spring Social的Facebook二次登录

最后修改: 2016年 11月 8日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we’ll focus on adding a new Facebook login to an existing form-login app.

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

We’re going to be using the Spring Social support to interact with Facebook and keep things clean and simple.

我们将使用Spring Social支持来与Facebook互动,并保持事情的干净和简单。

2. Maven Configuration

2.Maven配置

First, we will need to add spring-social-facebook dependency to our pom.xml:

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

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

3. Security Config – Just Form Login

3.安全配置 – 只需表格登录

Let’s first start from the simple security configuration where we just have form-based authentication:

让我们首先从简单的安全配置开始,我们只有基于表单的认证。

@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();
    } 
}

We’re not going to spend a lot of time on this config – if you want to understand it better, have a look at the form login article.

我们不打算在这个配置上花很多时间–如果你想更好地了解它,可以看看表单登录文章

4. The Facebook Properties

4.Facebook的属性

Next, let’s configure Facebook properties in our application.properties:

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

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

Note that:

请注意,。

  • We need to create a Facebook application to obtain appId and appSecret
  • From Facebook application Settings, make sure to Add Platform “Website” and http://localhost:8080/ is the “Site URL”

5. Security Config – Adding Facebook

5.安全配置 – 添加Facebook

Now, let’s add a new way to authenticate into the system – driven by 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);
    }
}

Let’s carefully look at the new config:

让我们仔细看一下新的配置。

  • we’re using a ProviderSignInController to enable the Facebook authentication, which needs two things:
    first, a ConnectionFactoryLocator registered as a FacebookConnectionFactory with the Facebook properties we defined earlier.
    second, an InMemoryUsersConnectionRepository.
  • by sending a POST to “/signin/facebook” – this controller will initiate a user sign-in using the Facebook service provider
  • we’re setting up a SignInAdapter to handle the login logic in our application
  • and we also setting up a ConnectionSignUp to handle signing up users implicitly when they first authenticate with Facebook

6. The Sign-In Adapter

6.签到适配器

Simply put, this adapter is a bridge between the controller above – driving the Facebook user sign-in flow – and our specific local application:

简单地说,这个适配器是上面的控制器–驱动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;
    }
}

Note that users logged-in using Facebook will have role FACEBOOK_USER, while users logged in using form will have role USER.

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

7. Connection Sign Up

7.连线签约

When a user authenticates with Facebook for the first time, they have no existing account in our application.

当用户第一次用Facebook认证时,他们在我们的应用程序中没有现有账户。

This is the point where we need to create that account automatically for them; we’re going to be using a ConnectionSignUp to drive that user creation logic:

这是我们需要为他们自动创建账户的地方;我们将使用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();
    }
}

As you can see, we created an account for the new user – using their DisplayName as username.

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

8. The Front End

8.前端

Finally, let’s take a look at our front end.

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

We’re going to now have support for these two authentication flows – form login and Facebook – on our login page:

我们现在要在我们的登录页面上支持这两种认证流程–表单登录和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>

Finally – here’s the index.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>

Note how this index page is displaying usernames and authorities.

注意这个索引页是如何显示用户名和权限的。

And that’s it – we now have two ways to authenticate into the application.

就这样–我们现在有两种方法来验证进入该应用程序。

9. Conclusion

9.结语

In this quick article, we learned how to use spring-social-facebook to implement a secondary authentication flow for our application.

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

And of course, as always, the source code is fully available over on GitHub.

当然,像往常一样,源代码在GitHub上是完全可用的