Spring?Security6.3.x的使用指南與注意事項(xiàng)
介紹
Spring Security 6.3.1 是一個(gè)重要的版本更新,它建立在 Spring Security 6 的核心現(xiàn)代化架構(gòu)之上,提供了更簡(jiǎn)潔的配置、更好的默認(rèn)安全性以及對(duì)最新安全標(biāo)準(zhǔn)的支持。以下是一個(gè) Spring Security 6.3.1 的使用指南,涵蓋核心概念、配置和常見(jiàn)任務(wù):
核心理念:
- Lambda DSL (推薦): Spring Security 6 開(kāi)始大力推廣基于 Lambda 的 DSL (領(lǐng)域特定語(yǔ)言) 配置方式,它更簡(jiǎn)潔、類型安全,并且避免了鏈?zhǔn)秸{(diào)用
.and()的繁瑣。這是當(dāng)前推薦的配置方式。 - 組件化: 安全配置被分解為更小、更專注的組件 (
SecurityFilterChain,UserDetailsService,PasswordEncoder,AuthenticationProvider等),提高了靈活性和可測(cè)試性。 - 默認(rèn)安全性增強(qiáng): 默認(rèn)配置提供了更強(qiáng)的安全防護(hù)(例如,默認(rèn)啟用 CSRF 保護(hù),更安全的會(huì)話管理)。
- Servlet 和 Reactive 分離: API 清晰區(qū)分了 Servlet (傳統(tǒng) Web) 和 Reactive (響應(yīng)式 WebFlux) 應(yīng)用的支持。
- OAuth2 和 OIDC 現(xiàn)代化: 對(duì) OAuth 2.1 和 OpenID Connect 1.0 提供了更現(xiàn)代、更符合規(guī)范的支持。
基礎(chǔ)配置 (Servlet 應(yīng)用 - 使用 Lambda DSL)
添加依賴 (Maven):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>3.2.0</version> <!-- Spring Boot 3.2.x 通常包含 Spring Security 6.3.x -->
</dependency>核心配置類 (SecurityConfig)
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity // 啟用 Spring Security Web 支持
public class SecurityConfig {
// 核心配置:定義安全過(guò)濾器鏈 (SecurityFilterChain)
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// 授權(quán)配置 (核心)
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/", "/home", "/public/**", "/css/**", "/js/**", "/images/**").permitAll() // 允許所有人訪問(wèn)
.requestMatchers("/user/**").hasRole("USER") // 需要 USER 角色
.requestMatchers("/admin/**").hasRole("ADMIN") // 需要 ADMIN 角色
.anyRequest().authenticated() // 其他所有請(qǐng)求都需要認(rèn)證
)
// 表單登錄配置
.formLogin(formLogin -> formLogin
//.loginPage("/login") // 自定義登錄頁(yè)路徑。不指定則使用默認(rèn)登錄頁(yè)
.permitAll() // 允許所有人訪問(wèn)登錄頁(yè)
.defaultSuccessUrl("/dashboard") // 登錄成功后的默認(rèn)跳轉(zhuǎn)頁(yè)
)
// 退出登錄配置
.logout(logout -> logout
.logoutUrl("/logout") // 退出登錄的 URL (默認(rèn)也是 /logout)
.logoutSuccessUrl("/login?logout") // 退出成功后的跳轉(zhuǎn)頁(yè)
.permitAll()
)
// 異常處理 (如訪問(wèn)拒絕)
.exceptionHandling(exceptionHandling -> exceptionHandling
.accessDeniedPage("/access-denied") // 自定義訪問(wèn)拒絕頁(yè)
)
// 啟用 HTTP Basic 認(rèn)證 (可選,常用于 API)
//.httpBasic(Customizer.withDefaults())
// 啟用 CSRF 保護(hù) (默認(rèn)啟用,對(duì)于 API 可能需要禁用)
//.csrf(csrf -> csrf.disable()); // 謹(jǐn)慎禁用!
return http.build();
}
// 配置內(nèi)存用戶存儲(chǔ) (僅用于演示/測(cè)試,生產(chǎn)環(huán)境用數(shù)據(jù)庫(kù))
@Bean
public UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) {
UserDetails user = User.builder()
.username("user")
.password(passwordEncoder.encode("password")) // 必須加密!
.roles("USER")
.build();
UserDetails admin = User.builder()
.username("admin")
.password(passwordEncoder.encode("adminpass"))
.roles("USER", "ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
// 配置密碼編碼器 (強(qiáng)制要求,不能使用明文!)
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(); // 推薦 BCrypt
// 其他選項(xiàng): Pbkdf2PasswordEncoder, SCryptPasswordEncoder, Argon2PasswordEncoder, DelegatingPasswordEncoder
}
}關(guān)鍵配置詳解(Lambda DSL)
authorizeHttpRequests(authorize -> authorize ...): 定義 URL 的訪問(wèn)規(guī)則。.requestMatchers(...).permitAll(): 匹配指定路徑模式,允許所有訪問(wèn)(包括匿名)。.requestMatchers(...).hasRole("ROLE")/.hasAuthority("AUTHORITY"): 匹配路徑,要求用戶擁有指定角色或權(quán)限。注意hasRole會(huì)自動(dòng)添加ROLE_前綴,所以配置里寫(xiě)USER對(duì)應(yīng)數(shù)據(jù)庫(kù)/用戶詳情中的ROLE_USER。hasAuthority則要求完全匹配字符串。.anyRequest().authenticated(): 匹配所有未在前面規(guī)則中匹配的請(qǐng)求,要求用戶已認(rèn)證(登錄)。.anyRequest().denyAll(): 匹配所有未在前面規(guī)則中匹配的請(qǐng)求,拒絕所有訪問(wèn)。
formLogin(formLogin -> formLogin ...): 配置基于表單的登錄。.loginPage("/login"): 指定自定義登錄頁(yè)面的 URL。不指定則使用Spring Security 默認(rèn)提供一個(gè)簡(jiǎn)單登錄頁(yè)。.loginProcessingUrl("/login"): 指定處理登錄表單提交的 URL(通常與登錄頁(yè)表單的action一致)。.defaultSuccessUrl("/dashboard", true): 登錄成功后重定向的 URL。第二個(gè)參數(shù)true表示總是重定向到此 URL,忽略登錄前訪問(wèn)的受保護(hù)頁(yè)面。.usernameParameter("username")/.passwordParameter("password"): 自定義表單中用戶名和密碼字段的名稱。.failureUrl("/login?error"): 登錄失敗后重定向的 URL。.permitAll(): 允許所有人訪問(wèn)登錄相關(guān)的端點(diǎn)。- 默認(rèn)登錄頁(yè)的注意事項(xiàng)
- 自動(dòng)生成位置
- 當(dāng)訪問(wèn)受保護(hù)資源時(shí),會(huì)自動(dòng)重定向到
/login - 無(wú)需創(chuàng)建控制器或視圖,Spring Security 自動(dòng)處理
- 當(dāng)訪問(wèn)受保護(hù)資源時(shí),會(huì)自動(dòng)重定向到
- 樣式限制
- 默認(rèn)頁(yè)面樣式非?;A(chǔ)(無(wú) CSS)
- 不適合生產(chǎn)環(huán)境,建議用于原型開(kāi)發(fā)或內(nèi)部工具
- 功能包含
- 包含 CSRF 令牌(默認(rèn)啟用)
- 顯示錯(cuò)誤消息(認(rèn)證失敗時(shí))
- 提供 “Remember me” 選項(xiàng)(需額外啟用)
- 啟用 “Remember me”
.rememberMe(remember -> remember
.key("uniqueAndSecretKey")
.tokenValiditySeconds(86400) // 1天
)logout(logout -> logout ...): 配置退出登錄。.logoutUrl("/logout"): 觸發(fā)退出登錄的 URL (默認(rèn)是/logout)。.logoutSuccessUrl("/login?logout"): 退出成功后的重定向 URL。.invalidateHttpSession(true): 是否使 HTTP Session 失效 (默認(rèn)true)。.deleteCookies("JSESSIONID"): 指定退出時(shí)要?jiǎng)h除的 Cookie 名稱。.permitAll(): 允許所有人訪問(wèn)退出端點(diǎn) (通常不需要認(rèn)證即可退出)。
exceptionHandling(exceptionHandling -> exceptionHandling ...): 處理安全異常。.accessDeniedPage("/access-denied"): 當(dāng)已認(rèn)證用戶訪問(wèn)其沒(méi)有權(quán)限的資源時(shí),重定向到指定頁(yè)面。.accessDeniedHandler(accessDeniedHandler): 使用自定義的AccessDeniedHandler處理訪問(wèn)拒絕。.authenticationEntryPoint(authenticationEntryPoint): 當(dāng)未認(rèn)證用戶嘗試訪問(wèn)受保護(hù)資源時(shí),使用自定義的AuthenticationEntryPoint處理 (如重定向到登錄頁(yè)或返回 401)。
httpBasic(Customizer.withDefaults()): 啟用 HTTP Basic 認(rèn)證。常用于 API。csrf(csrf -> csrf.disable()): 謹(jǐn)慎使用! 禁用 CSRF 保護(hù)。通常只在創(chuàng)建無(wú)狀態(tài) API (如 JWT) 時(shí)禁用。對(duì)于有 Session 的 Web 應(yīng)用,強(qiáng)烈建議保持啟用。
用戶認(rèn)證 (進(jìn)階)
UserDetailsService: 核心接口,用于根據(jù)用戶名加載用戶信息 (UserDetails)。你需要實(shí)現(xiàn)它來(lái)定義如何從你的數(shù)據(jù)源(數(shù)據(jù)庫(kù)、LDAP、外部服務(wù)等)加載用戶。
@Service
public class JpaUserDetailsService implements UserDetailsService {
private final UserRepository userRepository;
public JpaUserDetailsService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return userRepository.findByUsername(username)
.map(SecurityUser::new) // 將你的領(lǐng)域用戶轉(zhuǎn)換為 UserDetails
.orElseThrow(() -> new UsernameNotFoundException("User not found: " + username));
}
}- 確保你的
SecurityUser類實(shí)現(xiàn)了UserDetails接口,或直接使用 Spring Security 的User類(或其構(gòu)建器)來(lái)包裝你的領(lǐng)域用戶信息(用戶名、密碼、權(quán)限集合、是否啟用/過(guò)期/鎖定等)。 PasswordEncoder: 必須使用。負(fù)責(zé)密碼的加密存儲(chǔ)和驗(yàn)證。推薦BCryptPasswordEncoder。
@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder(); // 推薦:支持多種編碼,默認(rèn) BCrypt
// 或 return new BCryptPasswordEncoder();
}AuthenticationProvider(可選): 如果你想自定義認(rèn)證邏輯(例如,除了用戶名密碼還驗(yàn)證其他信息),可以實(shí)現(xiàn)AuthenticationProvider接口并注冊(cè)它。通常DaoAuthenticationProvider(使用UserDetailsService和PasswordEncoder) 已足夠。
方法級(jí)安全(Method Security)
- 啟用: 在配置類上添加
@EnableMethodSecurity。
@Configuration
@EnableMethodSecurity
public class MethodSecurityConfig {
// ...
}- 使用注解:
@PreAuthorize("hasRole('ADMIN')")/@PreAuthorize("hasAuthority('DELETE_USER')"): 在方法執(zhí)行前進(jìn)行權(quán)限檢查。支持 SpEL 表達(dá)式,非常靈活。@PostAuthorize: 在方法執(zhí)行后進(jìn)行權(quán)限檢查(例如,檢查返回值)。@Secured("ROLE_ADMIN"): 較舊的注解,只支持簡(jiǎn)單的角色列表,功能不如@PreAuthorize強(qiáng)大。@RolesAllowed("USER"): JSR-250 標(biāo)準(zhǔn)注解,類似于@Secured。
@Service
public class UserService {
@PreAuthorize("hasRole('ADMIN') or #id == authentication.principal.id") // SpEL 示例:允許管理員或用戶自己訪問(wèn)
public User getUserById(Long id) {
// ...
}
@PreAuthorize("hasAuthority('USER_DELETE')")
public void deleteUser(Long id) {
// ...
}
}OAuth2 / OIDC 資源服務(wù)器(保護(hù) API)
Spring Security 6 對(duì) OAuth2 資源服務(wù)器的配置進(jìn)行了顯著簡(jiǎn)化。
- 添加依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>- 配置 JWT 解碼器 (最常見(jiàn)): 在
application.properties/application.yml中配置頒發(fā)者 URI (issuer-uri) 或 JWK Set URI (jwk-set-uri)。Spring Boot 會(huì)自動(dòng)配置JwtDecoder。
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://your-auth-server.com/realms/your-realm # 或者 # spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://your-auth-server.com/jwks
- 配置資源服務(wù)器安全過(guò)濾器鏈:
@Bean
SecurityFilterChain resourceServerSecurityFilterChain(HttpSecurity http) throws Exception {
http
.securityMatcher("/api/**") // 只對(duì) /api/** 路徑應(yīng)用此安全配置
.authorizeHttpRequests(authorize -> authorize
.anyRequest().authenticated() // API 端點(diǎn)都需要認(rèn)證
)
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(Customizer.withDefaults()) // 使用 JWT 作為承載令牌格式
// .opaqueToken(Customizer.withDefaults()) // 使用不透明令牌
);
return http.build();
}Spring Security 會(huì)自動(dòng)使用配置的 JwtDecoder 驗(yàn)證 JWT 簽名、過(guò)期時(shí)間等,并提取聲明 (Claims) 構(gòu)建 JwtAuthenticationToken。
- 訪問(wèn)令牌中的信息: 在控制器或服務(wù)中,可以通過(guò)
@AuthenticationPrincipal注入Jwt對(duì)象或JwtAuthenticationToken
@GetMapping("/api/userinfo")
public Map<String, Object> getUserInfo(@AuthenticationPrincipal Jwt jwt) {
return Map.of(
"username", jwt.getSubject(),
"email", jwt.getClaimAsString("email"),
"scopes", jwt.getClaimAsStringList("scope")
);
}
最佳實(shí)踐與注意事項(xiàng)
- 始終使用
PasswordEncoder: 絕對(duì)不要存儲(chǔ)明文密碼。 - 最小權(quán)限原則: 只授予用戶完成工作所必需的權(quán)限。
- 保持依賴更新: Spring Security 會(huì)修復(fù)漏洞,及時(shí)更新到最新穩(wěn)定版。
- 理解 CSRF: 對(duì)于有狀態(tài) Web 應(yīng)用(使用 Session 和 Cookie),保持 CSRF 保護(hù)啟用。對(duì)于純無(wú)狀態(tài) API(如只使用 JWT 的 API),可以禁用 CSRF (
csrf.disable())。 - HTTPS: 在生產(chǎn)環(huán)境中始終使用 HTTPS。
- 安全頭: Spring Security 默認(rèn)設(shè)置了許多安全相關(guān)的 HTTP 響應(yīng)頭 (如
X-Content-Type-Options,X-Frame-Options,Strict-Transport-Security,Content-Security-Policy等)。理解并根據(jù)需要配置它們 (http.headers(headers -> headers ...))。 - 日志與監(jiān)控: 記錄安全相關(guān)事件(登錄成功/失敗、訪問(wèn)拒絕等)并進(jìn)行監(jiān)控。
- 避免
WebSecurityConfigurerAdapter: 在 Spring Security 5.7 中已棄用,在 6.x 中移除。始終使用SecurityFilterChainBean 配置。 - 謹(jǐn)慎使用
permitAll(): 確保只對(duì)真正公開(kāi)的資源使用它。 - 測(cè)試: 編寫(xiě)單元測(cè)試和集成測(cè)試來(lái)驗(yàn)證你的安全配置是否按預(yù)期工作。使用
@WithMockUser,@WithUserDetails,@WithAnonymousUser等注解進(jìn)行模擬用戶測(cè)試。
參考
- 官方文檔: 這是最權(quán)威、最新的信息來(lái)源。Spring Security 6.3.x 文檔(查看對(duì)應(yīng)版本的 Reference 和 Servlet 部分)
- Spring Boot Security Auto-configuration(了解 Boot 為你自動(dòng)配置了什么)
- Spring Security Samples: GitHub 上的官方示例
到此這篇關(guān)于Spring Security6.3.x使用指南的文章就介紹到這了,更多相關(guān)Spring Security6.3.x使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot3整合SpringSecurity6快速入門(mén)示例教程
- SpringSecurity6.4中一次性令牌登錄(One-Time Token Login)實(shí)現(xiàn)
- SpringBoot3.x接入Security6.x實(shí)現(xiàn)JWT認(rèn)證的完整步驟
- Spring Security6 最新版配置及實(shí)現(xiàn)動(dòng)態(tài)權(quán)限管理
- SpringSecurity6自定義JSON登錄的實(shí)現(xiàn)
- SpringSecurity6.x多種登錄方式配置小結(jié)
- Spring Security6配置方法(廢棄WebSecurityConfigurerAdapter)
- SpringBoot3.0+SpringSecurity6.0+JWT的實(shí)現(xiàn)
相關(guān)文章
Springboot如何利用攔截器攔截請(qǐng)求信息收集到日志詳解
一些系統(tǒng)經(jīng)常需要關(guān)注用戶請(qǐng)求的具體信息,如用戶信息、請(qǐng)求參數(shù)、響應(yīng)結(jié)果等等,在SpringBoot應(yīng)用中可通過(guò)攔截器的方式統(tǒng)一處理,下面這篇文章主要給大家介紹了關(guān)于Springboot如何利用攔截器攔截請(qǐng)求信息收集到日志的相關(guān)資料,需要的朋友可以參考下2021-08-08
Java rmi遠(yuǎn)程方法調(diào)用基本用法解析
這篇文章主要介紹了Java rmi遠(yuǎn)程方法調(diào)用基本用法解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05
SpringBoot項(xiàng)目中rest接口定義與參數(shù)傳遞和接收方式
本文介紹了使用RestClient測(cè)試接口的兩種方式:form-data和content-type,form-data適用于所有請(qǐng)求方式,但URL長(zhǎng)度有限制,content-type只適用于POST/DELETE/PUT請(qǐng)求,處理application/json格式參數(shù),對(duì)于參數(shù)較多的情況,建議使用JavaBean接收2026-04-04
通過(guò)代碼實(shí)例深入解析Java重寫(xiě)和重載
這篇文章主要介紹了通過(guò)代碼實(shí)例深入解析Java重寫(xiě)和重載,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11
Java動(dòng)態(tài)代理實(shí)現(xiàn)_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
動(dòng)態(tài)代理作為代理模式的一種擴(kuò)展形式,廣泛應(yīng)用于框架(尤其是基于AOP的框架)的設(shè)計(jì)與開(kāi)發(fā),本文將通過(guò)實(shí)例來(lái)講解Java動(dòng)態(tài)代理的實(shí)現(xiàn)過(guò)程2017-08-08
SpringBoot工程Docker多環(huán)境中使用同一個(gè)Jar包解決方案
在Docker多環(huán)境部署中,SpringBoot工程可以通過(guò)環(huán)境變量來(lái)動(dòng)態(tài)改變配置,無(wú)需重新打包,利用volume掛載或docker?cp命令,可以將配置文件直接傳入容器,提高部署效率,并保證安全性2024-09-09
JAVA(MAVEN項(xiàng)目)添加JUnit依賴配置全過(guò)程
在Maven項(xiàng)目中進(jìn)行單元測(cè)試是確保代碼質(zhì)量的重要步驟,本教程提供SpringBoot和微服務(wù)平臺(tái)適用的單元測(cè)試方法,包括環(huán)境準(zhǔn)備、創(chuàng)建測(cè)試類、JUnit簡(jiǎn)介及注解使用,環(huán)境準(zhǔn)備涉及引入依賴和安裝JUnit插件,測(cè)試類創(chuàng)建可通過(guò)快捷鍵或手動(dòng)添加@Test注解來(lái)實(shí)現(xiàn)2024-10-10
java實(shí)現(xiàn)socket客戶端連接服務(wù)端
本文是個(gè)人剛剛開(kāi)始學(xué)習(xí)如何通過(guò)socket去發(fā)送信息下邊的案例,也是書(shū)上的在這留下筆記,最后附上一個(gè)實(shí)例,有需要的小伙伴可以參考下。2015-10-10

