1. 概述
本教程是 對 Spring Security 配置的介紹,它允許用户在不使用 XML 的情況下輕鬆配置 Spring Security。
Java 配置已添加到 Spring Framework 中在 Spring 3.1 中,並擴展到 Spring Security 中在 Spring 3.2 中,並且定義在一個使用 @Configuration 註解標記的類中。
2. Maven 依賴項
為了將 Spring Security 集成到 Spring Boot 應用程序中,我們需要在我們的 pom.xml 中添加 spring-boot-starter-security 依賴項:<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
3. 使用 Java 配置進行 Web 安全性
我們先來看一個基本的 Spring Security Java 配置示例:@Configuration
public class SecurityConfig {
@Bean
public UserDetailsService inMemoryUserDetailsService(
PasswordEncoder passwordEncoder) {
UserDetails user = User.builder()
.username("user")
.password(passwordEncoder.encode("password"))
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
}
此配置類設置了一個基本的基於 Spring Security 的內存身份驗證機制。
它定義了一個用户名/密碼為 user/password 的單個用户,併為其分配了 USER 角色。我們使用 InMemoryUserDetailsManager,它將用户詳細信息存儲在內存中。此外,我們還需要一個 PasswordEncoder 豆以對用户密碼進行編碼:
@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
4. Web 安全
為了配置我們的授權規則和認證機制,我們發佈一個 SecurityFilterChain 豆:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authz) -> authz
.anyRequest().authenticated())
.httpBasic(withDefaults());
return http.build();
}
上述配置確保任何請求到應用程序都使用 HTTP 基本身份驗證。
現在,當我們啓動應用程序並導航到 http://localhost:8080/app/,將出現基本身份驗證登錄提示。輸入用户名 “user” 和密碼 “password”,服務器將驗證憑據。如果身份驗證成功,我們就可以訪問請求的資源。
5. 登錄表單
我們可以通過添加 formLogin DSL 調用到我們的聲明中,來添加基於瀏覽器的登錄和默認登錄頁面:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authz) -> authz
.anyRequest().authenticated())
.formLogin(withDefaults())
.httpBasic(withDefaults());
return http.build();
}
在啓動時,我們看到默認頁面已自動生成:
6. 使用角色進行授權
現在我們將使用角色配置每個 URL 的簡單授權:@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authz) -> authz
.requestMatchers("/").hasRole("USER")
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.formLogin(withDefaults())
.httpBasic(withDefaults());
return http.build();
}
這限制了對根目錄 (</) 的訪問,對於具有 </>ROLE_USER 角色 的用户,以及對於具有 </>ROLE_ADMIN 角色 的用户,同時任何經過身份驗證的用户都可以訪問網站的其餘部分。
請注意我們正在使用安全類型 API </>hasRole。
7. 登出
與 Spring Security 的許多其他方面一樣,登出也提供了框架的強大默認設置。
默認情況下,登出請求會失效會話,清除任何身份驗證緩存,清除 SecurityContextHolder,並重定向到登錄頁面。
以下是一個簡單的登出配置:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ...
.logout(withDefaults());
return http.build();
}
但是,如果我們想要對可用的處理程序獲得更多的控制,以下是一個更完整的實現:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http,
LogoutSuccessHandler webSecurityUserLogoutHandler)
throws Exception {
http
// ...
.logout((logout) -> logout
.logoutSuccessUrl("/")
.invalidateHttpSession(true)
.logoutSuccessHandler(webSecurityUserLogoutHandler)
.deleteCookies("JSESSIONID")
);
return http.build();
}
@Bean
public LogoutSuccessHandler webSecurityUserLogoutHandler() {
return (request, response, authentication) -> {
System.out.println("User logged out successfully!");
response.sendRedirect("/app");
};
}
此設置提供了一個乾淨且安全的登出過程,同時在處理登出後操作方面提供了靈活性。
8. 身份驗證
讓我們看看另一種使用 Spring Security 實現身份驗證的方式。
8.1. 內存身份驗證
回想一下,一開始我們使用了內存配置:
@Bean
public UserDetailsService inMemoryUserDetailsService(
PasswordEncoder passwordEncoder) {
UserDetails user = User.builder()
.username("user")
.password(passwordEncoder.encode("password"))
.roles("USER")
.build();
UserDetails admin = User.builder()
.username("admin")
.password(passwordEncoder.encode("password"))
.roles("ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
8.2. JDBC 身份驗證
為了將其遷移到 JDBC,首先,我們在我們的 pom.xml 中添加 h2 依賴項:
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
此外,我們需要在 application.properties 中配置 H2 數據庫:
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.h2.Driver
spring.sql.init.schema-locations=classpath:org/springframework/security/core/userdetails/jdbc/users.ddl
這定義了一個我們可以依賴的數據源,用於下一部分:
@Bean
public UserDetailsManager jdbcUserDetailsManager(DataSource dataSource,
PasswordEncoder passwordEncoder) {
JdbcUserDetailsManager jdbcUserDetailsManager = new JdbcUserDetailsManager(dataSource);
UserDetails user = User.builder()
.username("user")
.password(passwordEncoder.encode("password"))
.roles("USER")
.build();
UserDetails admin = User.builder()
.username("admin")
.password(passwordEncoder.encode("password"))
.roles("ADMIN")
.build();
jdbcUserDetailsManager.createUser(user);
jdbcUserDetailsManager.createUser(admin);
return jdbcUserDetailsManager;
}
此外,我們需要設置一個嵌入式 DataSource,該 DataSource 使用默認用户模式進行初始化。
當然,對於以上所有示例,我們也需要定義 PasswordEncoder 豆,如概述中所述。 Spring Security 在 org/springframework/security/core/userdetails/jdbc/users.ddl 中提供了一個。
我們使用 @Profile (inmemory 或 jdbc) 來選擇哪些 UserDetailsManager 豆應該處於活動狀態:
spring.profiles.active=inmemory
9. 結論
在本快速教程中,我們介紹了 Spring Security 的 Java 配置基礎知識,並重點講解了最簡單的配置場景的代碼示例。