1. 概述
在这个教程中,我们将专注于在现有表单登录应用中添加Facebook登录功能。我们将利用Spring Social库与Facebook交互,以保持代码简洁且易于理解。
2. Maven配置
首先,我们需要在pom.xml
文件中添加spring-social-facebook
依赖:
<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 {
@Autowired
private UserDetailsService userDetailsService;
@Bean
public AuthenticationManager authManager(HttpSecurity http) throws Exception {
return http.getSharedObject(AuthenticationManagerBuilder.class)
.userDetailsService(userDetailsService)
.and()
.build();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf()
.disable()
.authorizeRequests()
.antMatchers("/login*", "/signin/**", "/signup/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout();
return http.build();
}
}
我们不会在这部分花太多时间,如果你想深入了解,可以参考表单登录文章。
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 {
@Autowired
private FacebookConnectionSignup facebookConnectionSignup;
@Value("${spring.social.facebook.appSecret}")
String appSecret;
@Value("${spring.social.facebook.appId}")
String appId;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login*","/signin/**","/signup/**").permitAll()
...
return http.build();
}
@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身份验证,它需要两样东西:
首先,注册一个ConnectionFactoryLocator
,并将其命名为FacebookConnectionFactory
,使用我们之前定义的Facebook属性。
其次,使用一个InMemoryUsersConnectionRepository
。 - 发送一个
POST
到"/signin/facebook"
,这个控制器会通过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();
}
}
如你所见,我们为新用户创建了账户,使用他们的显示名称作为用户名。
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上找到完整版本。