1. 概述
在本教程中,我們將重點介紹如何將新的 Facebook 登錄功能添加到現有的表單登錄應用程序中。
我們將使用 Spring Social 支持與 Facebook 交互,並保持代碼簡潔易懂。
注意: Spring Social 庫已棄用;我們可以查看 Spring Security 5 – OAuth2 Login,它提供基於 OAuth2 的社交登錄功能。
2. Maven 配置
首先,我們需要將 <em >spring-social-facebook</em> 依賴添加到我們的 <em >pom.xml</em> 中:
<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。 - 通過向 “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. 前端 (Front End)
最後,讓我們來審視一下我們的前端。
現在,我們將為登錄頁面提供對這兩種身份驗證流程的支持——表單登錄和 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><p>最後 – 這是 <em >index.html</em>:</p>
<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 來為我們的應用程序實現輔助身份驗證流程。