雙Spring Security登錄頁面

Spring Security
Remote
1
12:53 AM · Nov 30 ,2025

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 上訪問上述示例。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.