1. 概述
在本快速教程中,我們將探討如何使用 Spring Security 安全地保護 Jakarta EE Web 應用程序。
2. Maven 依賴
讓我們從本教程所需的 Spring Security 依賴項開始:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>5.7.5</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>5.7.5</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>5.7.5</version>
</dependency>本教程編寫時,最新版本的 Spring Security 是 5.7.5;如往常一樣,我們可以在 Maven Central 上查看最新版本。
3. 安全配置
接下來,我們需要為現有的 Jakarta EE 應用程序設置安全配置:
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig {
@Bean
public InMemoryUserDetailsManager userDetailsService() {
UserDetails user = User.withUsername("user1")
.password("{noop}user1Pass")
.roles("USER")
.build();
UserDetails admin = User.withUsername("admin")
.password("{noop}adminPass")
.roles("ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
}為了簡化起見,我們實現了一個簡單的內存中認證。用户信息是硬編碼的。
這旨在用於快速原型設計,當不需要完整的持久化機制時。
接下來,讓我們通過添加 SecurityWebApplicationInitializer 類將安全性集成到現有系統中:
public class SecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
public SecurityWebApplicationInitializer() {
super(SpringSecurityConfig.class);
}
}此類將確保 SpringSecurityConfig 在應用程序啓動期間加載。 在此階段,我們已經實現了 Spring Security 的基本實現。 通過此實現,Spring Security 將默認要求所有請求和路由進行身份驗證。
4. 配置安全規則
我們可以通過創建 SecurityFilterChain 託管 Bean,進一步自定義 Spring Security:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf()
.disable()
.authorizeRequests()
.antMatchers("/auth/login*")
.anonymous()
.antMatchers("/home/admin*")
.hasRole("ADMIN")
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/auth/login")
.defaultSuccessUrl("/home", true)
.failureUrl("/auth/login?error=true")
.and()
.logout()
.logoutSuccessUrl("/auth/login");
return http.build();
}使用 antMatchers() 方法,我們配置 Spring Security 以允許匿名訪問 /auth/login 和任何其他請求。
4.1. 自定義登錄頁面
使用 formLogin() 方法配置自定義登錄頁面:
http.formLogin()
.loginPage("/auth/login")如果未指定,Spring Security 將生成默認登錄頁面在 /login。
<html>
<head></head>
<body>
<h1>Login</h1>
<form name='f' action="/auth/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><h3><strong>4.2. 自定義登陸頁面</strong></h3
<p>在成功登錄後,Spring Security會將用户重定向到應用程序的根目錄。我們可以通過指定默認成功URL來覆蓋此行為:</p>
http.formLogin()
.defaultSuccessUrl("/home", true)通過將 defaultSuccessUrl() 方法的 alwaysUse 參數設置為 true,用户將始終被重定向到指定的頁面。
如果 alwaysUse 參數未設置或設置為 false,用户將被重定向到他嘗試訪問的上一頁,在提示身份驗證之前。
同樣,我們也可以指定自定義失敗頁面:
http.formLogin()
.failureUrl("/auth/login?error=true")4.3. 授權
我們可以通過角色限制對資源的訪問:
http.formLogin()
.antMatchers("/home/admin*").hasRole("ADMIN")非管理員用户嘗試訪問 /home/admin 終點時,將會收到“訪問拒絕”錯誤。
我們還可以根據用户的角色在 JSP 頁面上限制數據。這通過使用 <security:authorize> 標籤來實現:
<security:authorize access="hasRole('ADMIN')">
This text is only visible to an admin
<br/>
<a href="<c:url value="/home/admin" />">Admin Page</a>
<br/>
</security:authorize>要使用此標籤,我們需要在頁面的頂部包含 Spring Security 標籤庫:
<%@ taglib prefix="security"
uri="http://www.springframework.org/security/tags" %>5. Spring Security XML 配置
我們之前已經探討了在 Java 中配置 Spring Security 的方法。現在,讓我們來看一個等效的 XML 配置。
首先,我們需要在 web/WEB-INF/spring 文件夾中創建一個 security.xml 文件,其中包含我們的 XML 配置。 這樣的 security.xml 配置文件的示例可以在文章末尾找到。
接下來,讓我們配置身份驗證管理器和身份驗證提供者。 為了簡化起見,我們使用硬編碼的簡單用户憑據:
<authentication-manager>
<authentication-provider>
<user-service>
<user name="user"
password="user123"
authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>我們剛才所做的是創建一個用户,該用户具有用户名、密碼和角色。
或者,我們可以使用密碼編碼器配置我們的身份驗證提供程序:
<authentication-manager>
<authentication-provider>
<password-encoder hash="sha"/>
<user-service>
<user name="user"
password="d7e6351eaa13189a5a3641bab846c8e8c69ba39f"
authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>我們還可以指定 Spring 的 UserDetailsService 的自定義實現或 Datasource 作為身份驗證提供者。 更多詳細信息請參考 這裏。
現在我們已經配置了身份驗證管理器,接下來我們設置安全規則並應用訪問控制:
<http auto-config='true' use-expressions="true">
<form-login default-target-url="/secure.jsp" />
<intercept-url pattern="/" access="isAnonymous()" />
<intercept-url pattern="/index.jsp" access="isAnonymous()" />
<intercept-url pattern="/secure.jsp" access="hasRole('ROLE_USER')" />
</http>在上述片段中,我們配置了 HttpSecurity 使用表單登錄,並將 /secure.jsp 設置為登錄成功 URL。我們授予匿名用户對 /index.jsp 和 / 路徑的訪問權限。 此外,我們指定對 /secure.jsp 的訪問需要身份驗證,並且經過身份驗證的用户至少應具有 ROLE_USER 級別的權限。
將 http 標籤的 auto-config 屬性設置為 true 會指示 Spring Security 實現默認行為,而無需在配置中覆蓋這些行為。 因此,/login 和 /logout 將分別用於用户登錄和註銷。 還提供了一個默認登錄頁面。
我們可以通過自定義登錄和註銷頁面,以及處理身份驗證成功和失敗的 URL,進一步自定義 form-login 標籤。 Security Namespace appendix 列出了 form-login (和其他) 標籤的所有可能屬性。 某些 IDE 還可以通過按住 ctrl 鍵點擊標籤進行檢查。
最後,為了在應用程序啓動期間加載 security.xml 配置,我們需要將以下定義添加到我們的 web.xml 中:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/*.xml
</param-value>
</context-param>
<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>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>請注意,在同一 JEE 應用中使用基於 XML 和 Java 的配置可能會導致錯誤。
6. 結論
在本文中,我們學習瞭如何使用 Spring Security 安全地保護 Jakarta EE 應用程序,並演示了基於 Java 和 XML 的配置方法。
我們還討論瞭如何根據用户角色授予或撤銷對特定資源的訪問權限。