全新Spring Security安全管理配置使用詳解
環(huán)境:SpringBoot2.7.12 + JDK21
1. 簡介
Spring Security 是一個(gè)提供身份驗(yàn)證、授權(quán)和防護(hù)常見攻擊的框架。它為確保命令式和反應(yīng)式應(yīng)用程序的安全提供一流的支持,是確?;?Spring 的應(yīng)用程序安全的事實(shí)標(biāo)準(zhǔn)。
Spring Scurity核心分為2大模塊:
- 認(rèn)證(Authentication):認(rèn)證是建立一個(gè)他聲明的主體的過程(一個(gè)主體一般是指用戶、設(shè)備或一些可以在你的應(yīng)用程序中執(zhí)行的其他系統(tǒng))。常見的身份認(rèn)證一般要求用戶提供用戶名和密碼。系統(tǒng)通過校驗(yàn)用戶名和密碼來完成認(rèn)證過程。
- 授權(quán)(Authorization):當(dāng)身份認(rèn)證通過后,去訪問系統(tǒng)的資源,系統(tǒng)會判斷用戶是否擁有訪問該資源的權(quán)限,只允許訪問有權(quán)限的系統(tǒng)資源,沒有權(quán)限的資源將無法訪問,這個(gè)過程叫用戶授權(quán)。比如會員管理模塊有增刪改查功能,有的用戶只能進(jìn)行查詢,而有的用戶可以進(jìn)行修改、刪除。一般來說,系統(tǒng)會為不同的用戶分配不同的角色,而每個(gè)角色則對應(yīng)一系列的權(quán)限。
從Spring Security5.7開始之前的安全配置方式及Web授權(quán)處理方式發(fā)生了變化,接下來將詳細(xì)介紹配置的變化。
2. 安全配置
2.1 配置方式
在5.7之前的版本自定義安全配置通過如下方式:
@Component
public class SecurityConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
// ...
}
}
在5.7之后推薦如下配置方式
@Configuration
public class SecurityConfig {
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
SecurityFilterChain controllerFilterChain(HttpSecurity http) throws Exception {
// ...
return http.build() ;
}
}
通過配置安全過濾器鏈的方式配置,具體內(nèi)部的配置細(xì)節(jié)還都是圍繞著HttpSecurity進(jìn)行配置。
2.2 配置不同的過濾器鏈
在一個(gè)配置文件中我們可以非常方便的配置多個(gè)過濾器鏈,針對不同的請求進(jìn)行攔截。
@Configuration
public class SecurityConfig {
@Bean
@Order(1)
SecurityFilterChain controllerFilterChain(HttpSecurity http) {
// 當(dāng)前過濾器鏈只對/demos/**, /login, /logout進(jìn)行攔截
http.requestMatchers(matchers -> matchers.antMatchers("/demos/**", "/login", "/logout")) ;
http.authorizeHttpRequests().antMatchers("/**").authenticated() ;
http.formLogin(Customizer.withDefaults()) ;
// ...
return http.build() ;
}
@Bean
@Order(2)
SecurityFilterChain managementSecurityFilterChain(HttpSecurity http) throws Exception {
// 該過濾器只會對/ac/**的請求進(jìn)行攔截
http.requestMatchers(matchers -> matchers.antMatchers("/ac/**")) ;
// ...
http.formLogin(Customizer.withDefaults());
return http.build();
}
}
以上配置了2個(gè)過濾器鏈,根據(jù)配置的@Order值,優(yōu)先級分別:controllerFilterChain,managementSecurityFilterChain。當(dāng)訪問除上面指定的uri模式以為的請求都將自動放行。
2.3 用戶驗(yàn)證配置
在5.7版本之前,我們通過如下配置配置內(nèi)存用戶
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.passwordEncoder(NoOpPasswordEncoder.getInstance())
.withUser("admin")
.password("123123")
.authorities(Arrays.asList(new SimpleGrantedAuthority("ROLE_ADMIN"))) ;
}
}
5.7 只有由于推薦的是通過自定義SecurityFilterChain的方式,所以我們需要通過如下的方式進(jìn)行配置:
@Configuration
public class SecurityConfig {
@Bean
@Order(0)
SecurityFilterChain controllerFilterChain(HttpSecurity http) throws Exception {
AuthenticationManagerBuilder builder = http.getSharedObject(AuthenticationManagerBuilder.class) ;
builder.inMemoryAuthentication()
.passwordEncoder(NoOpPasswordEncoder.getInstance())
.withUser("admin")
.password("123123")
.authorities(Arrays.asList(new SimpleGrantedAuthority("ROLE_ADMIN"))) ;
// ...
}
}
2.4 授權(quán)方式
在5.7之后推薦配置認(rèn)證授權(quán)的方式如下
@Bean
public SecurityFilterChain apiSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests().antMatchers("/users/**").hasAnyRole("ADMIN") ;
// ...
return http.build() ;
}
通過上面的authorizeHttpRequests方式進(jìn)行授權(quán)配置,會向過濾器鏈中添加AuthorizationFilter過濾器。在該過濾器中會進(jìn)行權(quán)限的驗(yàn)證。
2.5 自定義授權(quán)決策
如果需要對請求的uri進(jìn)行更加精確的匹配驗(yàn)證,如:/users/{id},需要驗(yàn)證只有這里的id值為666才方向。
@Bean
public SecurityFilterChain apiSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(registry -> {
registry.antMatchers("/users/{id}").access(new AuthorizationManager<RequestAuthorizationContext>() {
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication,
RequestAuthorizationContext object)
// 獲取路徑上的值信息,其中key=id,value=xxx
Map<String, String> variables
// 這里的第一個(gè)參數(shù)是boolean,確定了授權(quán)是否通過
return new AuthorityAuthorizationDecision(variables.get("id").equals("666"), Arrays.asList(new SimpleGrantedAuthority("D"))) ;
}
}) ;
}) ;
}
2.6 全局認(rèn)證
如果配置了多個(gè)不同的SecurityFilterChain,而每個(gè)認(rèn)證都使用相同的用戶體系,那么我們可以定義AuthenticationProvider或者UserDetailsService 類型的Bean即可。
@Bean
UserDetailsService userDetailsService() {
return new UserDetailsService() {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return null;
}
} ;
}
@Bean
AuthenticationProvider authenticationProvider() {
return new AuthenticationProvider() {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
return null;
}
@Override
public boolean supports(Class<?> authentication) {
return false;
}
} ;
}
以上是本篇文章的全部內(nèi)容, 希望對你有所幫助。
完畢?。?!