Spring Boot構(gòu)建系統(tǒng)安全層的步驟
01 | Spring Security 架構(gòu)及核心類(lèi)
Spring Security 中的過(guò)濾器鏈
Spring Security 中采用的是管道-過(guò)濾器(Pipe-Filter)架構(gòu)模式,這些過(guò)濾器鏈,構(gòu)成了 Spring Security 的核心。如下圖所示:

項(xiàng)目一旦啟動(dòng),過(guò)濾器鏈將會(huì)實(shí)現(xiàn)自動(dòng)配置,如下圖所示:

UsernamePasswordAuthenticationFilter 用來(lái)檢查輸入的用戶(hù)名和密碼,代碼如下:
public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response)
throws AuthenticationException {
if (postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException(
"Authentication method not supported: " + request.getMethod());
}
String username = obtainUsername(request);
String password = obtainPassword(request);
if (username == null) {
username = "";
}
if (password == null) {
password = "";
}
username = username.trim();
UsernamePasswordAuthenticationToken authRequest =
new UsernamePasswordAuthenticationToken(username, password);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
…
}
BasicAuthenticationFilter 用來(lái)認(rèn)證用戶(hù)的身份。
FilterSecurityInterceptor 用來(lái)判定該請(qǐng)求是否能夠訪問(wèn)目標(biāo) HTTP 端點(diǎn)。
Spring Security 中的核心類(lèi)

SecurityContextHolder 存儲(chǔ)了應(yīng)用的安全上下文對(duì)象 SecurityContext,包含系統(tǒng)請(qǐng)求中最近使用的認(rèn)證信息。
一個(gè) HTTP 請(qǐng)求到達(dá)系統(tǒng)后,將通過(guò)一系列的 Filter 完成用戶(hù)認(rèn)證,然后具體的工作交由 AuthenticationManager 完成,AuthenticationManager 成功驗(yàn)證后會(huì)返回填充好的 Authentication 實(shí)例。
AuthenticationManager 是一個(gè)接口,其實(shí)現(xiàn)類(lèi) ProviderManager 會(huì)進(jìn)一步依賴(lài) AuthenticationProvider 接口完成具體的認(rèn)證工作。
在 Spring Security 中存在一大批 AuthenticationProvider 接口的實(shí)現(xiàn)類(lèi),分別完成各種認(rèn)證操作。在執(zhí)行具體的認(rèn)證工作時(shí),Spring Security 勢(shì)必會(huì)使用用戶(hù)詳細(xì)信息,UserDetailsService 服務(wù)就是用來(lái)對(duì)用戶(hù)詳細(xì)信息實(shí)現(xiàn)管理。
02 | 基于 Spring Security 構(gòu)建用戶(hù)認(rèn)證體系
在 Spring Boot 中整合 Spring Security 框架首先需要引入依賴(lài):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
只要我們?cè)诖a工程中添加了上述依賴(lài),包含在該工程中的所有 HTTP 端點(diǎn)都將被保護(hù)起來(lái)。
在引入 spring-boot-starter-security 依賴(lài)之后,Spring Security 會(huì)默認(rèn)創(chuàng)建一個(gè)用戶(hù)名為“user”的賬號(hào)。當(dāng)我們?cè)L問(wèn) AccountController 的 “accounts/{accountId}” 端點(diǎn)時(shí),彈出如下界面:

同時(shí),控制臺(tái)日志打印如下:
Using generated security password: 17bbf7c4-456a-48f5-a12e-a680066c8f80
因此,訪問(wèn)該接口需要設(shè)置如下信息:

每次啟動(dòng)應(yīng)用時(shí),通過(guò) Spring Security 自動(dòng)生成的密碼都會(huì)有所變化。如果我們想設(shè)置登錄賬號(hào)和密碼,可以在 application.yml 中配置如下:
spring:
security:
user:
name: springcss
password: springcss_password
配置 Spring Security
初始化用戶(hù)信息所依賴(lài)的配置類(lèi)是 WebSecurityConfigurer 接口,在日常開(kāi)發(fā)中,我們往往是使用 WebSecurityConfigurerAdapter 類(lèi)并覆寫(xiě)其中的 configure(AuthenticationManagerBuilder auth) 的方法完成配置工作。
使用 AuthenticationManagerBuilder 類(lèi)創(chuàng)建一個(gè) AuthenticationManager 就能夠輕松實(shí)現(xiàn)基于內(nèi)存、LADP 和 JDBC 的驗(yàn)證。初始化所使用的用戶(hù)信息只需要指定用戶(hù)名(Username)、密碼(Password)和角色(Role)這三項(xiàng)數(shù)據(jù)即可。
使用基于內(nèi)存的用戶(hù)信息存儲(chǔ)方案
@Override
protected void configure(AuthenticationManagerBuilder builder) throws Exception {
builder.inMemoryAuthentication()
.withUser("springcss_user")
.password("password1")
// 或者使用.authorities("ROLE_USER")
.roles("USER")
.and()
.withUser("springcss_admin")
.password("password2")
.roles("USER", "ADMIN");
}
使用基于數(shù)據(jù)庫(kù)的用戶(hù)信息存儲(chǔ)方案
表結(jié)構(gòu)如下:
create table users( username varchar_ignorecase(50) not null primary key, password varchar_ignorecase(500) not null, enabled boolean not null ); create table authorities ( username varchar_ignorecase(50) not null, authority varchar_ignorecase(50) not null, constraint fk_authorities_users foreign key(username) references users(username) ); create unique index ix_auth_username on authorities (username,authority);
Spring Security 的配置代碼如下:
@Autowired
DataSource dataSource;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery("select username, password, enabled from Users where username=?")
.authoritiesByUsernameQuery("select username, authority from UserAuthorities where username=?")
.passwordEncoder(new BCryptPasswordEncoder());
}
實(shí)現(xiàn)定制化用戶(hù)認(rèn)證方案
擴(kuò)展 UserDetails
public class SpringCssUser implements UserDetails {
private static final long serialVersionUID = 1L;
private Long id;
private final String username;
private final String password;
private final String phoneNumber;
// 省略getter/setter
// 省略重寫(xiě)方法
}
擴(kuò)展 UserDetailsService
@Service
public class SpringCssUserDetailsService implements UserDetailsService {
@Autowired
private SpringCssUserRepository repository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
SpringCssUser user = repository.findByUsername(username);
if (user != null) {
return user;
}
throw new UsernameNotFoundException("SpringCSS User '" + username + "' not found");
}
}
整合定制化配置
@Configuration
public class SpringCssSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
SpringCssUserDetailsService springCssUserDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(springCssUserDetailsService);
}
}
03 | 基于 Spring Security 實(shí)現(xiàn)安全訪問(wèn)
在日常開(kāi)發(fā)過(guò)程中,我們需要對(duì) Web 應(yīng)用中的不同 HTTP 端點(diǎn)進(jìn)行不同粒度的權(quán)限控制。
對(duì) HTTP 端點(diǎn)進(jìn)行訪問(wèn)授權(quán)管理
使用配置方法
配置方法也是位于 WebSecurityConfigurerAdapter 類(lèi)中,但使用的是 configure(HttpSecurity http) 方法,如下代碼所示:
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// 所有請(qǐng)求都需要認(rèn)證
.anyRequest()
// 允許認(rèn)證用戶(hù)訪問(wèn)
.authenticated()
.and()
// 需要使用表單進(jìn)行登錄
.formLogin()
.and()
// 使用 HTTP Basic Authentication 方法完成認(rèn)證
.httpBasic();
}
Spring Security 還提供了一個(gè) access() 方法,允許開(kāi)發(fā)人員傳入一個(gè)表達(dá)式進(jìn)行更細(xì)粒度的權(quán)限控制,這里,我們將引入Spring 框架提供的一種動(dòng)態(tài)表達(dá)式語(yǔ)言—— SpEL(Spring Expression Language 的簡(jiǎn)稱(chēng))。
只要 SpEL 表達(dá)式的返回值為 true,access() 方法就允許用戶(hù)訪問(wèn),如下代碼所示:
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/orders")
.access("hasRole('ROLE_USER')");
}
使用注解
Spring Security 提供了 @PreAuthorize 注解也可以實(shí)現(xiàn)類(lèi)似的效果,使用該注解代碼如下所示:
@RestController
@RequestMapping(value="orders")
public class OrderController {
@PostMapping(value = "/")
@PreAuthorize("hasRole(ROLE_ADMIN)")
public void addOrder(@RequestBody Order order) {
…
}
}
@PostAuthorize 主要用于請(qǐng)求結(jié)束之后檢查權(quán)限。
實(shí)現(xiàn)多維度訪問(wèn)授權(quán)方案
使用用戶(hù)級(jí)別保護(hù)服務(wù)訪問(wèn)
該級(jí)別是最基本的資源保護(hù)級(jí)別,只要是認(rèn)證用戶(hù)就可能訪問(wèn)服務(wù)內(nèi)的各種資源。
@Configuration
public class SpringCssSecurityConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.authenticated();
}
}
使用用戶(hù)+角色級(jí)別保護(hù)服務(wù)訪問(wèn)
該級(jí)別在認(rèn)證用戶(hù)級(jí)別的基礎(chǔ)上,還要求用戶(hù)屬于某一個(gè)或多個(gè)特定角色。
@Configuration
public class SpringCssSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/customers/**")
.hasRole("ADMIN")
.anyRequest()
.authenticated();
}
}
上述代碼表示只有"ADMIN"角色的認(rèn)證用戶(hù)才能訪問(wèn)以"/customers/"為根地址的所有 URL。
使用用戶(hù)+角色+操作級(jí)別保護(hù)服務(wù)訪問(wèn)
該級(jí)別在認(rèn)證用戶(hù)+角色級(jí)別的基礎(chǔ)上,對(duì)某些 HTTP 操作方法做了訪問(wèn)限制。
@Configuration
public class SpringCssSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception{
http.authorizeRequests()
.antMatchers(HttpMethod.DELETE, "/customers/**")
.hasRole("ADMIN")
.anyRequest()
.authenticated();
}
}
上述代碼的效果在于對(duì)“/customers”端點(diǎn)執(zhí)行刪除操作時(shí),我們需要使用具有“ADMIN”角色的“springcss_admin”用戶(hù),否則會(huì)出現(xiàn)“access_denied”錯(cuò)誤信息。
以上就是Spring Boot構(gòu)建系統(tǒng)安全層的步驟的詳細(xì)內(nèi)容,更多關(guān)于Spring Boot構(gòu)建系統(tǒng)安全層的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Docker?快速部署Springboot項(xiàng)目超詳細(xì)最新版
- IDEA Spring Boot 自動(dòng)化構(gòu)建+部署的實(shí)現(xiàn)
- SpringBoot集成Swagger2構(gòu)建在線API文檔的代碼詳解
- SpringBoot集成Swagger構(gòu)建api文檔的操作
- Spring Boot 2.4 新特性之一鍵構(gòu)建Docker鏡像的過(guò)程詳解
- Spring Boot 使用 Swagger 構(gòu)建 RestAPI 接口文檔
- IDEA使用Gradle構(gòu)建SpringBoot項(xiàng)目工程的詳細(xì)教程
- springboot-2.3.x最新版源碼閱讀環(huán)境搭建(基于gradle構(gòu)建)
- 基于SpringBoot構(gòu)建電商秒殺項(xiàng)目代碼實(shí)例
- Spring Boot2如何構(gòu)建可部署的war包
相關(guān)文章
Springboot日志配置的實(shí)現(xiàn)示例
本文主要介紹了Springboot日志配置的實(shí)現(xiàn)示例,使用slf4j和logback的方式記錄日志,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-08-08
Java多線程中常見(jiàn)的幾個(gè)問(wèn)題
這篇文章主要介紹了Java多線程中常見(jiàn)的幾個(gè)問(wèn)題 ,需要的朋友可以參考下2015-05-05
spring mvc使用@InitBinder標(biāo)簽對(duì)表單數(shù)據(jù)綁定的方法
這篇文章主要介紹了spring mvc使用@InitBinder標(biāo)簽對(duì)表單數(shù)據(jù)綁定的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-03-03
MAC 系統(tǒng)如何使用 Sublime Text 2 直接編譯運(yùn)行 java 代碼
這篇文章主要介紹了MAC 系統(tǒng)如何使用 Sublime Text 2 直接編譯運(yùn)行 java 代碼,需要的朋友可以參考下2014-10-10
SpringBoot整合log4j日志與HashMap的底層原理解析
這篇文章主要介紹了SpringBoot整合log4j日志與HashMap的底層原理,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01
http調(diào)用controller方法時(shí)openfeign執(zhí)行流程
這篇文章主要為大家介紹了http調(diào)用controller方法時(shí)openfeign執(zhí)行流程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07
springboot實(shí)現(xiàn)郵箱發(fā)送(激活碼)功能的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用springboot實(shí)現(xiàn)郵箱發(fā)送(激活碼)功能,文中的示例代碼簡(jiǎn)潔易懂,有需要的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-10-10
Java Servlet中Response對(duì)象的使用方法
本文介紹了Java Servlet中Response對(duì)象的使用方法,包括設(shè)置響應(yīng)頭、設(shè)置響應(yīng)編碼、向客戶(hù)端發(fā)送數(shù)據(jù)、重定向等操作,同時(shí)介紹了常用的響應(yīng)狀態(tài)碼和響應(yīng)類(lèi)型,幫助讀者更好地理解和掌握Servlet中Response對(duì)象的用法2023-05-05

