Spring Security 框架最佳實(shí)踐
一、什么是 Spring Security?
Spring Security 是一個(gè)功能強(qiáng)大、高度可定制的身份驗(yàn)證(Authentication)和訪問控制(Authorization)框架,是保護(hù)基于 Spring 的應(yīng)用的事實(shí)標(biāo)準(zhǔn)。
? 核心功能:
- 用戶登錄認(rèn)證(Authentication)
- 權(quán)限控制、角色控制(Authorization)
- 防止 CSRF、會(huì)話固定、點(diǎn)擊劫持等攻擊
- 支持多種登錄方式:表單登錄、HTTP Basic、OAuth2、JWT、LDAP 等
- 與 Spring Boot 無縫集成
二、Spring Security 核心概念
1.Authentication(認(rèn)證)
- 代表“當(dāng)前用戶是誰”,包含用戶名、密碼、權(quán)限等。
- 由
AuthenticationManager管理認(rèn)證過程。
2.UserDetails&UserDetailsService
UserDetails:封裝用戶信息(用戶名、密碼、權(quán)限、是否鎖定等)UserDetailsService:根據(jù)用戶名加載UserDetails
@Override
public UserDetails loadUserByUsername(String username) {
// 從數(shù)據(jù)庫查用戶 → 返回 UserDetails(含加密密碼 + 權(quán)限)
}3.PasswordEncoder
- 用于加密密碼和比對密碼。
- 永遠(yuǎn)不要存儲(chǔ)明文密碼!
- 常用實(shí)現(xiàn):
BCryptPasswordEncoder,SCryptPasswordEncoder,Pbkdf2PasswordEncoder
// 注冊時(shí): user.setPassword(passwordEncoder.encode(rawPassword)); // 登錄時(shí)(框架自動(dòng)調(diào)用): passwordEncoder.matches(rawPassword, encodedPassword); // true/false
4.GrantedAuthority
- 代表一個(gè)權(quán)限,如
"ROLE_ADMIN"、"user:delete"。 - 通常以
ROLE_開頭表示角色,其它表示具體權(quán)限。
5.SecurityContext&SecurityContextHolder
- 存儲(chǔ)當(dāng)前登錄用戶的信息(
Authentication對象)。 - 可在任何地方獲取當(dāng)前用戶:
Authentication auth = SecurityContextHolder.getContext().getAuthentication(); String username = auth.getName();
三、Spring Security 工作流程(認(rèn)證過程)

sequenceDiagram
participant User
participant Filter as FilterChain (Spring Security)
participant Provider as AuthenticationProvider
participant Service as UserDetailsService
participant Encoder as PasswordEncoder
User->>Filter: 提交用戶名/密碼
Filter->>Provider: 調(diào)用 authenticate()
Provider->>Service: loadUserByUsername(username)
Service-->>Provider: 返回 UserDetails(含加密密碼)
Provider->>Encoder: matches(輸入密碼, 數(shù)據(jù)庫加密密碼)
alt 匹配成功
Encoder-->>Provider: true
Provider-->>Filter: 返回認(rèn)證成功 Authentication
Filter->>User: 登錄成功,跳轉(zhuǎn)
else 匹配失敗
Encoder-->>Provider: false
Provider-->>Filter: 拋出異常
Filter->>User: 登錄失敗
end四、常用配置方式(Spring Boot)
1. 引入依賴(Maven)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>2. 基礎(chǔ)配置類(啟用 Web 安全)
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authz -> authz
.requestMatchers("/login", "/register", "/css/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/user/**").hasAnyRole("USER", "ADMIN")
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login") // 自定義登錄頁
.defaultSuccessUrl("/home") // 登錄成功跳轉(zhuǎn)
.permitAll()
)
.logout(logout -> logout
.logoutSuccessUrl("/login?logout")
.permitAll()
);
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(); // 推薦使用 BCrypt
}
}3. 自定義 UserDetailsService
@Component
public class MyUserServiceImpl implements UserDetailsService {
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userMapper.findUserByName(username);
if (user == null) throw new UsernameNotFoundException("用戶不存在");
// ? 直接返回?cái)?shù)據(jù)庫中的加密密碼(注冊時(shí)已加密存儲(chǔ)?。?
return User.builder()
.username(user.getUsername())
.password(user.getSupwd()) // ← 不要再 encode!
.roles("USER") // 或者 .authorities(getAuthorities())
.build();
}
}五、權(quán)限控制(授權(quán) Authorization)
1. 方法級(jí)別權(quán)限(推薦)
@Service
public class ArticleService {
@PreAuthorize("hasRole('ADMIN')") // 需要 ADMIN 角色
public void deleteArticle(Long id) {
// ...
}
@PreAuthorize("hasAuthority('article:edit')") // 需要具體權(quán)限
public void editArticle(Article article) {
// ...
}
@PostAuthorize("returnObject.owner == authentication.name")
public Article getArticle(Long id) {
// 返回后檢查:只有文章主人才能看
}
}?? 要啟用方法級(jí)權(quán)限,需在配置類加:
@EnableMethodSecurity
@Configuration
@EnableWebSecurity
@EnableMethodSecurity // ← 啟用 @PreAuthorize 等注解
public class SecurityConfig { ... }2. 頁面級(jí)別權(quán)限(Thymeleaf)
<!-- 只有 ADMIN 能看到 -->
<div sec:authorize="hasRole('ADMIN')">
<a href="/admin" rel="external nofollow" >管理后臺(tái)</a>
</div>
<!-- 顯示當(dāng)前用戶名 -->
<span sec:authentication="name"></span>需引入:
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity6</artifactId>
</dependency>六、常見自定義擴(kuò)展
1. 自定義登錄成功/失敗處理器
@Component
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws IOException {
response.sendRedirect("/home?loginSuccess");
}
}在配置中使用:
.formLogin(form -> form
.successHandler(mySuccessHandler)
.failureHandler(myFailureHandler)
)2. 自定義權(quán)限異常處理
@Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
response.sendRedirect("/403");
}
}配置:
.exceptionHandling(ex -> ex
.accessDeniedHandler(myAccessDeniedHandler)
)七、與 JWT / 前后端分離集成(簡要)
如果你是前后端分離項(xiàng)目(如 Vue + Spring Boot),通常不用 Session,改用 JWT:
- 用戶 POST
/login提交用戶名密碼 - 后端驗(yàn)證成功 → 生成 JWT Token 返回
- 前端后續(xù)請求在 Header 中攜帶
Authorization: Bearer <token> - 后端用 Filter 解析 Token → 設(shè)置
SecurityContext
?? 此時(shí)
UserDetailsService依然有用 —— 用于從 Token 中的用戶名加載用戶權(quán)限!
八、最佳實(shí)踐 & 注意事項(xiàng)
| 項(xiàng)目 | 建議 |
|---|---|
| 密碼存儲(chǔ) | 必須加密(BCrypt 最常用) |
| 密碼比對 | 交給 Spring Security,不要手動(dòng)比對 |
| 權(quán)限設(shè)計(jì) | 角色(ROLE_) + 細(xì)粒度權(quán)限(user:delete)結(jié)合 |
| 登錄頁 | 可自定義,但路徑要 permitAll |
| CSRF | 表單登錄默認(rèn)開啟,JWT 項(xiàng)目可關(guān)閉 |
| 調(diào)試 | 可臨時(shí) .authorizeHttpRequests(authz -> authz.anyRequest().permitAll()) 放行所有 |
? 總結(jié)一句話:
Spring Security = 認(rèn)證(你是誰)+ 授權(quán)(你能干什么)+ 安全防護(hù),你只需要提供“用戶數(shù)據(jù)”和“權(quán)限規(guī)則”,框架自動(dòng)完成驗(yàn)證和攔截。
?? 學(xué)習(xí)路徑建議:
- 先跑通表單登錄 + 自定義 UserDetailsService
- 學(xué)會(huì)配置 URL 權(quán)限控制
- 掌握方法級(jí)權(quán)限
@PreAuthorize - 學(xué)習(xí)自定義處理器(登錄成功/失敗、無權(quán)限)
- 進(jìn)階:JWT、OAuth2、方法權(quán)限表達(dá)式、動(dòng)態(tài)權(quán)限
?? 送你一個(gè)完整可運(yùn)行的最小示例結(jié)構(gòu):
src/
├── controller/
│ └── LoginController.java // 登錄頁、首頁
├── service/
│ └── MyUserServiceImpl.java // loadUserByUsername
├── config/
│ └── SecurityConfig.java // 權(quán)限配置 + PasswordEncoder
└── entity/
└── User.java // 用戶實(shí)體(含加密密碼字段)到此這篇關(guān)于Spring Security 框架的文章就介紹到這了,更多相關(guān)spring security 框架內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 最新Spring Security實(shí)戰(zhàn)教程之Spring Security安全框架指南
- SpringBoot集成SpringSecurity安全框架方式
- 一文帶你掌握Spring Security框架的使用
- Spring Security實(shí)現(xiàn)基于角色的訪問控制框架
- 一文詳解Spring?security框架的使用
- SpringSecurity概念及整合ssm框架的示例詳解
- Spring?Security安全框架之記住我功能
- SpringBoot整合Security實(shí)現(xiàn)權(quán)限控制框架(案例詳解)
- 詳解Springboot2.3集成Spring security 框架(原生集成)
相關(guān)文章
Java中String的split切割字符串方法實(shí)例及擴(kuò)展
最近在項(xiàng)目中遇到一個(gè)小問題,一個(gè)字符串分割成一個(gè)數(shù)組,下面這篇文章主要給大家介紹了關(guān)于Java中String的split切割字符串方法的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2022-06-06
java實(shí)現(xiàn)簡單登錄界面的實(shí)戰(zhàn)過程
學(xué)習(xí)JAVA的過程當(dāng)中,登陸界面是多數(shù)人第一個(gè)實(shí)現(xiàn)的小程序,下面這篇文章主要給大家介紹了關(guān)于利用java實(shí)現(xiàn)簡單登錄界面的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-05-05
JavaWeb中struts2實(shí)現(xiàn)文件上傳下載功能實(shí)例解析
這篇文章主要介紹了JavaWeb中struts2文件上傳下載功能的實(shí)現(xiàn),在Web應(yīng)用系統(tǒng)開發(fā)中,文件上傳和下載功能是非常常用的功能,需要的朋友可以參考下2016-05-05
如何解決IDEA使用Tomcat控制臺(tái)中文出現(xiàn)亂碼問題
這篇文章主要介紹了如何解決IDEA使用Tomcat控制臺(tái)中文出現(xiàn)亂碼問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09
SpringBoot中的ApplicationRunner與CommandLineRunner問題
這篇文章主要介紹了SpringBoot中的ApplicationRunner與CommandLineRunner問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09
Java 數(shù)據(jù)結(jié)構(gòu)與算法系列精講之KMP算法
在很多地方也都經(jīng)常看到講解KMP算法的文章,看久了好像也知道是怎么一回事,但總感覺有些地方自己還是沒有完全懂明白。這兩天花了點(diǎn)時(shí)間總結(jié)一下,有點(diǎn)小體會(huì),我希望可以通過我自己的語言來把這個(gè)算法的一些細(xì)節(jié)梳理清楚,也算是考驗(yàn)一下自己有真正理解這個(gè)算法2022-02-02
Java ConcurrentHashMap鎖分段機(jī)制使用及代碼實(shí)例
ConcurrentHashMap是Java中的一種線程安全的哈希表,通過鎖分段機(jī)制提高了并發(fā)性能,在Java 8中,ConcurrentHashMap引入了CAS操作和更復(fù)雜的節(jié)點(diǎn)繼承結(jié)構(gòu),進(jìn)一步優(yōu)化了并發(fā)操作2025-01-01
Java實(shí)現(xiàn)微信掃碼登入的實(shí)例代碼
這篇文章主要介紹了java實(shí)現(xiàn)微信掃碼登入功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06

