1. 簡介
在本教程中,我們將學習如何使用兩個不同的 Spring Security http 元素配置,以支持兩個不同的登錄頁面,配置 Spring Security。
2. 配置 2 個 HTTP 元素
在我們需要一個應用程序的管理員頁面和一個普通用户頁面時,我們可能需要兩個登錄頁面。
我們將配置兩個 http 元素,這些元素將通過關聯的 URL 模式進行區分:
- /user* 用於需要普通用户身份驗證才能訪問的頁面
- /admin* 用於由管理員訪問的頁面
每個 http 元素將具有不同的登錄頁面和不同的登錄處理 URL。
為了配置兩個不同的 http 元素,讓我們創建兩個靜態類,這些類已使用 @Configuration 註解進行標註。
它們將被放置在常規 @Configuration 類中:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
...
}
讓我們定義用於“ADMIN”用户的 ConfigurerAdapter:
@Configuration
@Order(1)
public static class App1ConfigurationAdapter {
@Bean
public SecurityFilterChain filterChainApp1(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector);
http.securityMatcher("/admin*")
.authorizeHttpRequests(authorizationManagerRequestMatcherRegistry ->
authorizationManagerRequestMatcherRegistry.requestMatchers(mvcMatcherBuilder.pattern("/admin*")).hasRole("ADMIN"))
// log in
.formLogin(httpSecurityFormLoginConfigurer ->
httpSecurityFormLoginConfigurer.loginPage("/loginAdmin")
.loginProcessingUrl("/admin_login")
.failureUrl("/loginAdmin?error=loginError")
.defaultSuccessUrl("/adminPage"))
// logout
.logout(httpSecurityLogoutConfigurer ->
httpSecurityLogoutConfigurer.logoutUrl("/admin_logout")
.logoutSuccessUrl("/protectedLinks")
.deleteCookies("JSESSIONID"))
.exceptionHandling(httpSecurityExceptionHandlingConfigurer ->
httpSecurityExceptionHandlingConfigurer.accessDeniedPage("/403"))
.csrf(AbstractHttpConfigurer::disable);
return http.build();
}
}
現在,讓我們定義用於普通用户的 ConfigurerAdapter:
@Configuration
@Order(2)
public static class App2ConfigurationAdapter {
@Bean
public SecurityFilterChain filterChainApp2(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector);
http.securityMatcher("/user*")
.authorizeHttpRequests(authorizationManagerRequestMatcherRegistry ->
authorizationManagerRequestMatcherRegistry.requestMatchers(mvcMatcherBuilder.pattern("/user*")).hasRole("USER"))
// log in
.formLogin(httpSecurityFormLoginConfigurer ->
httpSecurityFormLoginConfigurer.loginPage("/loginUser")
.loginProcessingUrl("/user_login")
.failureUrl("/loginUser?error=loginError")
.defaultSuccessUrl("/userPage"))
// logout
.logout(httpSecurityLogoutConfigurer ->
httpSecurityLogoutConfigurer.logoutUrl("/user_logout")
.logoutSuccessUrl("/protectedLinks")
.deleteCookies("JSESSIONID"))
.exceptionHandling(httpSecurityExceptionHandlingConfigurer ->
httpSecurityExceptionHandlingConfigurer.accessDeniedPage("/403"))
.csrf(AbstractHttpConfigurer::disable);
return http.build();
}
}
請注意,通過在每個靜態類上放置 @Order 註解,我們正在指定根據 URL 請求時進行匹配的兩個類將以何種順序進行考慮。
兩個配置類不能具有相同的順序。
3. 自定義登錄頁面
我們將為每種類型的用户創建自定義登錄頁面。對於管理員用户,登錄表單將具有 “user_login” 操作,如配置中定義:
<p>用户登錄頁面</p>
<form name="f" action="user_login" method="POST">
<table>
<tr>
<td>用户:</td>
<td><input type="text" name="username" value=""></td>
</tr>
<tr>
<td>密碼:</td>
<td><input type="password" name="password" /></td>
</tr>
<tr>
<td><input name="submit" type="submit" value="submit" /></td>
</tr>
</table>
</form>
管理員登錄頁面與此類似,但表單將具有 “admin_login” 操作,如 java 配置中定義。
4. 身份驗證配置
現在我們需要為我們的應用程序配置身份驗證。讓我們看看兩種實現方法——一種使用常見的用户身份驗證源,另一種使用兩個獨立的源。
4.1. 使用常見的用户身份驗證源
如果兩個登錄頁面共享一個常見的用户身份驗證源,則可以創建一個類型為 UserDetailsService的單個 Bean,該 Bean 將處理身份驗證。
讓我們使用 InMemoryUserDetailsManager來演示此場景,該管理器定義了兩個用户——一個具有“USER”角色,另一個具有“ADMIN”角色:
@Bean
public UserDetailsService userDetailsService() throws Exception {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User
.withUsername("user")
.password(encoder().encode("userPass"))
.roles("USER")
.build());
manager.createUser(User
.withUsername("admin")
.password(encoder().encode("adminPass"))
.roles("ADMIN")
.build());
return manager;
}
@Bean
public static PasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
在這種情況下,來自上一部分的 UserDetailsService Bean 將不再被使用。
6. 結論
在本快速教程中,我們展示瞭如何在同一 Spring Security 應用程序中實現兩種不同的登錄頁面。
運行應用程序時,您可以在 /protectedLinks URI 上訪問上述示例。