Spring Boot構(gòu)建系統(tǒng)安全層的步驟
01 | Spring Security 架構(gòu)及核心類
Spring Security 中的過濾器鏈
Spring Security 中采用的是管道-過濾器(Pipe-Filter)架構(gòu)模式,這些過濾器鏈,構(gòu)成了 Spring Security 的核心。如下圖所示:
項目一旦啟動,過濾器鏈將會實現(xiàn)自動配置,如下圖所示:
UsernamePasswordAuthenticationFilter 用來檢查輸入的用戶名和密碼,代碼如下:
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 用來認證用戶的身份。
FilterSecurityInterceptor 用來判定該請求是否能夠訪問目標 HTTP 端點。
Spring Security 中的核心類
SecurityContextHolder 存儲了應(yīng)用的安全上下文對象 SecurityContext,包含系統(tǒng)請求中最近使用的認證信息。
一個 HTTP 請求到達系統(tǒng)后,將通過一系列的 Filter 完成用戶認證,然后具體的工作交由 AuthenticationManager 完成,AuthenticationManager 成功驗證后會返回填充好的 Authentication 實例。
AuthenticationManager 是一個接口,其實現(xiàn)類 ProviderManager 會進一步依賴 AuthenticationProvider 接口完成具體的認證工作。
在 Spring Security 中存在一大批 AuthenticationProvider 接口的實現(xiàn)類,分別完成各種認證操作。在執(zhí)行具體的認證工作時,Spring Security 勢必會使用用戶詳細信息,UserDetailsService 服務(wù)就是用來對用戶詳細信息實現(xiàn)管理。
02 | 基于 Spring Security 構(gòu)建用戶認證體系
在 Spring Boot 中整合 Spring Security 框架首先需要引入依賴:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
只要我們在代碼工程中添加了上述依賴,包含在該工程中的所有 HTTP 端點都將被保護起來。
在引入 spring-boot-starter-security 依賴之后,Spring Security 會默認創(chuàng)建一個用戶名為“user”的賬號。當我們訪問 AccountController 的 “accounts/{accountId}” 端點時,彈出如下界面:
同時,控制臺日志打印如下:
Using generated security password: 17bbf7c4-456a-48f5-a12e-a680066c8f80
因此,訪問該接口需要設(shè)置如下信息:
每次啟動應(yīng)用時,通過 Spring Security 自動生成的密碼都會有所變化。如果我們想設(shè)置登錄賬號和密碼,可以在 application.yml 中配置如下:
spring: security: user: name: springcss password: springcss_password
配置 Spring Security
初始化用戶信息所依賴的配置類是 WebSecurityConfigurer 接口,在日常開發(fā)中,我們往往是使用 WebSecurityConfigurerAdapter 類并覆寫其中的 configure(AuthenticationManagerBuilder auth) 的方法完成配置工作。
使用 AuthenticationManagerBuilder 類創(chuàng)建一個 AuthenticationManager 就能夠輕松實現(xiàn)基于內(nèi)存、LADP 和 JDBC 的驗證。初始化所使用的用戶信息只需要指定用戶名(Username)、密碼(Password)和角色(Role)這三項數(shù)據(jù)即可。
使用基于內(nèi)存的用戶信息存儲方案
@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ù)庫的用戶信息存儲方案
表結(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()); }
實現(xiàn)定制化用戶認證方案
擴展 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 // 省略重寫方法 }
擴展 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 實現(xiàn)安全訪問
在日常開發(fā)過程中,我們需要對 Web 應(yīng)用中的不同 HTTP 端點進行不同粒度的權(quán)限控制。
對 HTTP 端點進行訪問授權(quán)管理
使用配置方法
配置方法也是位于 WebSecurityConfigurerAdapter 類中,但使用的是 configure(HttpSecurity http) 方法,如下代碼所示:
protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() // 所有請求都需要認證 .anyRequest() // 允許認證用戶訪問 .authenticated() .and() // 需要使用表單進行登錄 .formLogin() .and() // 使用 HTTP Basic Authentication 方法完成認證 .httpBasic(); }
Spring Security 還提供了一個 access() 方法,允許開發(fā)人員傳入一個表達式進行更細粒度的權(quán)限控制,這里,我們將引入Spring 框架提供的一種動態(tài)表達式語言—— SpEL(Spring Expression Language 的簡稱)。
只要 SpEL 表達式的返回值為 true,access() 方法就允許用戶訪問,如下代碼所示:
@Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/orders") .access("hasRole('ROLE_USER')"); }
使用注解
Spring Security 提供了 @PreAuthorize 注解也可以實現(xiàn)類似的效果,使用該注解代碼如下所示:
@RestController @RequestMapping(value="orders") public class OrderController { @PostMapping(value = "/") @PreAuthorize("hasRole(ROLE_ADMIN)") public void addOrder(@RequestBody Order order) { … } }
@PostAuthorize 主要用于請求結(jié)束之后檢查權(quán)限。
實現(xiàn)多維度訪問授權(quán)方案
使用用戶級別保護服務(wù)訪問
該級別是最基本的資源保護級別,只要是認證用戶就可能訪問服務(wù)內(nèi)的各種資源。
@Configuration public class SpringCssSecurityConfig extends WebSecurityConfigurerAdapter { protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .anyRequest() .authenticated(); } }
使用用戶+角色級別保護服務(wù)訪問
該級別在認證用戶級別的基礎(chǔ)上,還要求用戶屬于某一個或多個特定角色。
@Configuration public class SpringCssSecurityConfig extends WebSecurityConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/customers/**") .hasRole("ADMIN") .anyRequest() .authenticated(); } }
上述代碼表示只有"ADMIN"角色的認證用戶才能訪問以"/customers/"為根地址的所有 URL。
使用用戶+角色+操作級別保護服務(wù)訪問
該級別在認證用戶+角色級別的基礎(chǔ)上,對某些 HTTP 操作方法做了訪問限制。
@Configuration public class SpringCssSecurityConfig extends WebSecurityConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception{ http.authorizeRequests() .antMatchers(HttpMethod.DELETE, "/customers/**") .hasRole("ADMIN") .anyRequest() .authenticated(); } }
上述代碼的效果在于對“/customers”端點執(zhí)行刪除操作時,我們需要使用具有“ADMIN”角色的“springcss_admin”用戶,否則會出現(xiàn)“access_denied”錯誤信息。
以上就是Spring Boot構(gòu)建系統(tǒng)安全層的步驟的詳細內(nèi)容,更多關(guān)于Spring Boot構(gòu)建系統(tǒng)安全層的資料請關(guān)注腳本之家其它相關(guān)文章!
- Docker?快速部署Springboot項目超詳細最新版
- IDEA Spring Boot 自動化構(gòu)建+部署的實現(xiàn)
- SpringBoot集成Swagger2構(gòu)建在線API文檔的代碼詳解
- SpringBoot集成Swagger構(gòu)建api文檔的操作
- Spring Boot 2.4 新特性之一鍵構(gòu)建Docker鏡像的過程詳解
- Spring Boot 使用 Swagger 構(gòu)建 RestAPI 接口文檔
- IDEA使用Gradle構(gòu)建SpringBoot項目工程的詳細教程
- springboot-2.3.x最新版源碼閱讀環(huán)境搭建(基于gradle構(gòu)建)
- 基于SpringBoot構(gòu)建電商秒殺項目代碼實例
- Spring Boot2如何構(gòu)建可部署的war包
相關(guān)文章
詳解java8在Collection中新增加的方法removeIf
這篇文章主要介紹了詳解java8在Collection中新增加的方法removeIf的相關(guān)資料,需要的朋友可以參考下2018-01-01springboot中swagger、異步/定時/郵件任務(wù)的問題
這篇文章主要介紹了springboot中swagger、異步/定時/郵件任務(wù)的問題,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-07-07引入QQ郵箱發(fā)送驗證碼進行安全校驗功能實現(xiàn)
最近遇到這樣的需求用戶輸入自己的郵箱,點擊獲取驗證碼,后臺會發(fā)送一封郵件到對應(yīng)郵箱中,怎么實現(xiàn)呢?下面小編給大家?guī)砹艘隥Q郵箱發(fā)送驗證碼進行安全校驗功能,需要的朋友可以參考下2023-02-02解決spirngboot連接redis報錯:READONLY?You?can‘t?write?against?
docker部署的redis,springboot基本每天來連redis都報錯:READONLY?You?can't?write?against?a?read?only?replica,重啟redis后,可以正常連接。但是每天都重啟redis,不現(xiàn)實,也很麻煩,今天給大家分享解決方式,感興趣的朋友一起看看吧2023-06-06Java實現(xiàn)excel大數(shù)據(jù)量導入
這篇文章主要為大家詳細介紹了Java實現(xiàn)excel大數(shù)據(jù)量導入,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-08-08Spring配置文件解析之BeanDefinitionParserDelegate詳解
這篇文章主要介紹了Spring配置文件解析之BeanDefinitionParserDelegate詳解,對于Spring的配置文件的解析處理操作是在BeanDefinitionParserDelegate中進行處理操作,接下來我們簡單介紹一下BeanDefinitionParserDelegate所做的處理操作,需要的朋友可以參考下2024-02-02