知識庫 / Spring / Spring MVC RSS 訂閱

Spring Security 表單登錄

Spring MVC,Spring Security
HongKong
9
03:12 PM · Dec 06 ,2025

1. 引言

本教程將重點介紹使用 Spring Security 進行登錄。我們將在此之前的 Spring MVC 示例基礎上進行擴展,因為該示例是設置 Web 應用程序以及登錄機制的必要組成部分。

2. Maven 依賴

在使用 Spring Boot 時,<a href="https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-security">spring-boot-starter-security</a> starter 會自動包含所有依賴項,例如 <em>spring-security-core</em>, <em>spring-security-web</em>, 和 <em>spring-security-config</em> 等:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
    <version>2.3.3.RELEASE</version>
</dependency>

如果未使用 Spring Boot,請參閲 Spring Security with Maven 文章,其中介紹瞭如何添加所有必需的依賴項。標準 spring-security-webspring-security-config 均需要包含。

3. Spring Security Java 配置

首先,我們創建一個 Spring Security 配置類,該類會創建一個 SecurityFilterChain 實例。

通過添加 @EnableWebSecurity 註解,我們獲得 Spring Security 與 MVC 集成支持:

@Configuration
@EnableWebSecurity
public class SecSecurityConfig {

    @Bean
    public InMemoryUserDetailsManager userDetailsService() {
        // InMemoryUserDetailsManager (see below)
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        // http builder configurations for authorize requests and form login (see below)
    }
}

在本示例中,我們使用了內存式身份驗證,並定義了三個用户。

接下來,我們將探討我們用於創建登錄配置表單的元素。

讓我們首先構建我們的身份驗證管理器。

3.1. InMemoryUserDetailsManager

身份提供者由一個簡單的、基於內存的實現 InMemoryUserDetailsManager 支持。這在尚未必要時,用於快速原型設計非常有用:

    @Bean
    public InMemoryUserDetailsManager userDetailsService() {
        UserDetails user1 = User.withUsername("user1")
            .password(passwordEncoder().encode("user1Pass"))
            .roles("USER")
            .build();
        UserDetails user2 = User.withUsername("user2")
            .password(passwordEncoder().encode("user2Pass"))
            .roles("USER")
            .build();
        UserDetails admin = User.withUsername("admin")
            .password(passwordEncoder().encode("adminPass"))
            .roles("ADMIN")
            .build();
        return new InMemoryUserDetailsManager(user1, user2, admin);
    }

在這裏,我們將配置三個用户,用户名、密碼和角色都硬編碼。

從 Spring 5 開始,我們還需要定義密碼編碼器

在我們的示例中,我們將使用 BCryptPasswordEncoder

@Bean 
public PasswordEncoder passwordEncoder() { 
    return new BCryptPasswordEncoder(); 
}

接下來,讓我們配置 HttpSecurity

3.2. 配置請求授權

我們將首先進行必要的配置以授權請求。

在這裏,我們允許匿名訪問 /login</em/>,以便用户進行身份驗證。我們將限制對 /admin</em/> 的訪問至 ADMIN</em/> 角色,並對其他一切進行安全保護:

   @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.csrf()
            .disable()
            .authorizeRequests()
            .antMatchers("/admin/**")
            .hasRole("ADMIN")
            .antMatchers("/anonymous*")
            .anonymous()
            .antMatchers("/login*")
            .permitAll()
            .anyRequest()
            .authenticated()
            .and()
            // ...
    }

請注意,antMatchers() 元素的順序很重要;更具體的規則需要先定義,然後才是更通用的規則

3.3. 表單登錄配置

接下來,我們將擴展上述配置以支持表單登錄和登出:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
      // ...
      .and()
      .formLogin()
      .loginPage("/login.html")
      .loginProcessingUrl("/perform_login")
      .defaultSuccessUrl("/homepage.html", true)
      .failureUrl("/login.html?error=true")
      .failureHandler(authenticationFailureHandler())
      .and()
      .logout()
      .logoutUrl("/perform_logout")
      .deleteCookies("JSESSIONID")
      .logoutSuccessHandler(logoutSuccessHandler());
      return http.build();
}
<ul>
 <li><em>loginPage()</em> – 自定義登錄頁面</li>
 <li><em>loginProcessingUrl()</em> – 將用户名和密碼提交到的 URL</li>
 <li><em>defaultSuccessUrl()</em> – 成功登錄後的目標頁面</li>
 <li><em>failureUrl()</em> – 登錄失敗後的目標頁面</li>
 <li><em>logoutUrl()</em> – 自定義註銷</li>
</ul>

4. 將 Spring Security 添加到 Web 應用程序

為了使用上述定義的 Spring Security 配置,我們需要將其附加到 Web 應用程序中。

我們將使用 <em >WebApplicationInitializer</em >>,因此我們無需提供 <em >web.xml</em >>

public class AppInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext sc) {

        AnnotationConfigWebApplicationContext root = new AnnotationConfigWebApplicationContext();
        root.register(SecSecurityConfig.class);

        sc.addListener(new ContextLoaderListener(root));

        sc.addFilter("securityFilter", new DelegatingFilterProxy("springSecurityFilterChain"))
          .addMappingForUrlPatterns(null, false, "/*");
    }
}

請注意,如果我們在使用 Spring Boot 應用程序,則此初始化器並非必需。有關 Spring Boot 中安全配置如何加載的更多詳細信息,請參閲我們關於 Spring Boot 安全自動配置的文章。

5. Spring Security XML 配置

讓我們也來查看對應的 XML 配置。

整個項目使用 Java 配置,因此我們需要通過一個 Java @Configuration 類導入 XML 配置文件:

@Configuration
@ImportResource({ "classpath:webSecurityConfig.xml" })
public class SecSecurityConfig {
   public SecSecurityConfig() {
      super();
   }
}

Spring Security XML 配置,webSecurityConfig.xml:

<http use-expressions="true">
    <intercept-url pattern="/login*" access="isAnonymous()" />
    <intercept-url pattern="/**" access="isAuthenticated()"/>

    <form-login login-page='/login.html' 
      default-target-url="/homepage.html" 
      authentication-failure-url="/login.html?error=true" />
    <logout logout-success-url="/login.html" />
</http>

<authentication-manager>
    <authentication-provider>
        <user-service>
            <user name="user1" password="user1Pass" authorities="ROLE_USER" />
        </user-service>
        <password-encoder ref="encoder" />
    </authentication-provider>
</authentication-manager>

<beans:bean id="encoder" 
  class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
</beans:bean>

6. web.xml**

在 Spring 4 之前,我們通常在 web.xml 中配置 Spring Security,即為標準的 Spring MVC web.xml 添加一個額外的過濾器:

<display-name>Spring Secured Application</display-name>

<!-- Spring MVC -->
<!-- ... -->

<!-- Spring Security -->
<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

過濾器 – DelegatingFilterProxy – 僅會委託給由 Spring 管理的 Bean – 即 FilterChainProxy – 該 Bean 本身能夠受益於完整的 Spring Bean 生命週期管理以及相關功能。

7. 登錄表單

登錄表單頁面將使用 Spring MVC 的簡單機制,通過將視圖名稱映射到 URL 來進行註冊。 此外,不需要在視圖和控制器之間進行顯式的控制器:

registry.addViewController("/login.html");

當然,這對應於 login.jsp

<html>
<head></head>
<body>
   <h1>Login</h1>
   <form name='f' action="login" method='POST'>
      <table>
         <tr>
            <td>User:</td>
            <td><input type='text' name='username' value=''></td>
         </tr>
         <tr>
            <td>Password:</td>
            <td><input type='password' name='password' /></td>
         </tr>
         <tr>
            <td><input name="submit" type="submit" value="submit" /></td>
         </tr>
      </table>
  </form>
</body>
</html>

Spring 登錄表單包含以下相關工件:

  • login – 表單通過 POST 請求發起的身份驗證流程的 URL
  • username – 用户名
  • password – 密碼

8. 進一步配置 Spring 登錄

我們在介紹上文的 Spring Security 配置時,簡要討論了一些登錄機制的配置。現在我們來更深入地探討一下。

覆蓋大多數 Spring Security 的默認配置的原因是為了 隱藏應用程序使用了 Spring Security。我們還希望儘量減少潛在攻擊者對應用程序所知的信息。

完全配置後,登錄元素如下所示:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.formLogin()
      .loginPage("/login.html")
      .loginProcessingUrl("/perform_login")
      .defaultSuccessUrl("/homepage.html",true)
      .failureUrl("/login.html?error=true")
    return http.build();
}

或者對應的XML配置:

<form-login 
  login-page='/login.html' 
  login-processing-url="/perform_login" 
  default-target-url="/homepage.html"
  authentication-failure-url="/login.html?error=true" 
  always-use-default-target="true"/>

8.1. 登錄頁面

接下來,我們將使用 loginPage() 方法 配置一個自定義登錄頁面:

http.formLogin()
  .loginPage("/login.html")

同樣,我們也可以使用XML配置:

login-page='/login.html'

如果未指定此項,Spring Security將在login URL 生成一個非常基本的登錄表單。

8.2. 登錄 POST URL

Spring 登錄默認的 POST URL 用於觸發身份驗證過程,為 /login。在此之前,該 URL 為 /j_spring_security_check。這與 Spring Security 4 之前的版本不同(參見 從 Spring Security 3 遷移到 Spring Security 4)。

我們可以使用 loginProcessingUrl 方法來覆蓋此 URL。

http.formLogin()
  .loginProcessingUrl("/perform_login")

我們還可以使用XML配置:

login-processing-url="/perform_login"

通過覆蓋默認 URL,我們隱藏了該應用程序實際上使用 Spring Security 加密的事實。該信息不應對外暴露。

8.3. 成功頁面

在成功登錄後,您將被重定向到一個頁面,默認情況下是 Web 應用程序的根目錄。

可以通過調用 defaultSuccessUrl() 方法來覆蓋此設置:

http.formLogin()
  .defaultSuccessUrl("/homepage.html")

或者使用XML配置:

default-target-url="/homepage.html"

如果 always-use-default-target 屬性設置為 true,則用户始終會被重定向到該頁面。如果該屬性設置為 false,則用户將被重定向到他們之前想要訪問的上一頁,然後再提示進行身份驗證。

8.4. 登錄失敗頁面

類似於登錄頁面,登錄失敗頁面由 Spring Security 默認在 /login?error 路徑下自動生成。

要覆蓋此行為,可以使用 failureUrl() 方法:

http.formLogin()
  .failureUrl("/login.html?error=true")

或者使用XML:

authentication-failure-url="/login.html?error=true"

9. 結論

在《Spring 登錄示例》中,我們配置了一個簡單的身份驗證流程。我們還討論了 Spring Security 登錄表單、安全配置以及一些高級自定義選項。

當項目在本地運行時,示例 HTML 可以通過以下地址訪問:

http://localhost:8080/spring-security-mvc-login/login.html
user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.