Spring Security常用配置的使用解讀
Spring Security 是 Spring 家族為我們提供的一款安全管理的框架,它是一個(gè)功能強(qiáng)大并且可以靈活定制的身份驗(yàn)證和訪問控制框架。Spring Security 側(cè)重于為 Java 應(yīng)用程序提供身份驗(yàn)證和授權(quán)。與所有 Spring 項(xiàng)目一樣,Spring Security 的真正強(qiáng)大之處在于它非常容易擴(kuò)展來滿足我們的不同需求。
在 SSM 時(shí)代,Spring Security 因?yàn)榉爆嵉呐渲枚槐蝗藗兂S茫窃?Spring Boot 中為提供了自動(dòng)化配置方案,可以零配置使用 Spring Security。
初體驗(yàn)
在 pom.xml 中導(dǎo)入 maven 依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
只要在項(xiàng)目中加入 Spring Security 的依賴,項(xiàng)目中的所有接口都會(huì)被保護(hù)起來了。
當(dāng)我們訪問我們的項(xiàng)目的時(shí)候,就會(huì)先來到 Spring Security 默認(rèn)的登錄頁面,

默認(rèn)的用戶名是 user,密碼會(huì)在控制臺(tái)打印,

登錄后就可以正常訪問項(xiàng)目了。
自定義用戶名密碼
因?yàn)槊艽a是隨機(jī)生成的一段密鑰,不方便記憶,所以我們可以自己配置用戶名和密碼。
配置用戶名和密碼的方式有三種,我們可以在配置文件中配置,也可以在 Java 代碼中配置,還可以在數(shù)據(jù)庫中配置,我們先看如何在配置文件中配置。
使用配置文件配置
使用配置文件配置比較簡單,直接在 application.yml 中配置即可。
spring:
security:
user:
name: user
password: 1234使用 Java 代碼配置
使用 Java 代碼配置也比較簡單,我們只需要編寫一個(gè) SecurityConfig 配置類,重寫一個(gè) configure() 方法即可。
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("user").password("$2a$10$zwUhw4cAEv1AH6auayRPbePJAKk87peABiKegNMp4mqKXWxJZyDQS").roles("user")
.and()
.withUser("admin").password("$2a$10$mDQiCHTt3RLV.pLozBKOBOVIe7kaa3vYUCqZUu.957mpomdztOr0y").roles("admin");
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}使用 Java 代碼配置比較靈活,我們可以用 and() 方法來配置多個(gè)用戶。
在 Spring 5 以后要求我們配置的密碼必須是加密的,我們可以配置一個(gè) BCryptPasswordEncoder 密碼編碼器來幫助我們加密密碼,我們只需要在單元測試中創(chuàng)建一個(gè) BCryptPasswordEncoder 密碼編碼器,調(diào)用它的 encode()方法來加密,把得到的值復(fù)制到代碼中,然后再將這個(gè)密碼編碼器配置到容器中,這個(gè)密碼編碼器的的好處是即使是相同的字段也可以得到不同的結(jié)果。
自定義攔截規(guī)則
因?yàn)?Spring Security 默認(rèn)攔截所有的請求,但我們實(shí)際項(xiàng)目中肯定不能這樣,所以我們應(yīng)該自定義攔截規(guī)則,針對不同的請求,制定不同的處理方式。
這就需要用到 HttpSecurity 的配置,我們只需要在配置類中實(shí)現(xiàn)重載的 configure() 方法
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests() // 驗(yàn)證請求
// 路徑匹配,參數(shù)是要處理的 url
.antMatchers("/admin/**").hasRole("admin") // 要具有某種權(quán)限
.antMatchers("/user/**").hasAnyRole("admin", "user")// 要具有某種權(quán)限中的一種
.anyRequest().authenticated();
}
}登錄注銷配置
Spring Security 為我們提供的絕不止上面的那么簡單,我們通過配置 HttpSecurity 還可以定制登錄接口,登錄成功后的響應(yīng),登錄失敗后的響應(yīng)以及注銷的相關(guān)操作。
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.formLogin()
// 登錄處理接口
.loginProcessingUrl("/login")
// 定義登錄頁面,未登錄時(shí),訪問一個(gè)需要登錄之后才能訪問的接口,會(huì)自動(dòng)跳轉(zhuǎn)到該頁面
.loginPage("/login")
// 定義登錄時(shí),用戶名的 key,默認(rèn)為 username
.usernameParameter("uname")
// 定義登錄時(shí),用戶密碼的 key,默認(rèn)為 password
.passwordParameter("passwd")
// 登錄成功的處理器
.successHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
Map<String, Object> map = new HashMap<>();
map.put("status", 200);
map.put("msg", authentication.getPrincipal());
out.write(new ObjectMapper().writeValueAsString(map));
out.flush();
out.close();
}
})
// 登錄失敗的處理器
.failureHandler(new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
Map<String, Object> map = new HashMap<>();
map.put("status", 401);
if (e instanceof LockedException) {
map.put("msg", "賬戶被鎖定,登錄失敗!");
} else if (e instanceof BadCredentialsException) {
map.put("msg", "用戶名或密碼輸入錯(cuò)誤,登錄失??!");
} else if (e instanceof DisabledException) {
map.put("msg", "賬戶被禁用,登錄失敗!");
} else if (e instanceof AccountExpiredException) {
map.put("msg", "賬戶過期,登錄失?。?);
} else if (e instanceof CredentialsExpiredException) {
map.put("msg", "密碼過期,登錄失??!");
} else {
map.put("msg", "登錄失敗!");
}
out.write(new ObjectMapper().writeValueAsString(map));
out.flush();
out.close();
}
})
// 和表單登錄相關(guān)的接口統(tǒng)統(tǒng)都直接通過
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
// 注銷成功的處理器
.logoutSuccessHandler(new LogoutSuccessHandler() {
@Override
public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
Map<String, Object> map = new HashMap<>();
map.put("status", 200);
map.put("msg", "注銷登錄成功!");
out.write(new ObjectMapper().writeValueAsString(map));
out.flush();
out.close();
}
});
}
}方法安全
Spring Security 還為我們提供了方法級別安全的配置,什么是方法安全呢?就是在調(diào)用方法的時(shí)候來進(jìn)行驗(yàn)證和授權(quán)。怎么實(shí)現(xiàn)方法安全呢?
首先我們要在配置類上加一個(gè)注解 @EnableGlobalMethodSecurity,
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
}并將 prePostEnabled 和 securedEnabled 兩個(gè)屬性值設(shè)置為 true,接下來就可以在方法上加注解來進(jìn)行權(quán)限控制了。
我們先寫一個(gè) MethodService
@Service
public class MethodService {
@PreAuthorize("hasRole('admin')")
public String admin() {
return "hello admin";
}
@Secured("ROLE_user")
public String user() {
return "hello user";
}
@PreAuthorize("hasAnyRole('admin', 'user')")
public String hello() {
return "hello hello";
}
}用@PreAuthorize 注解和@Secured 注解來控制方法的訪問權(quán)限,再寫一個(gè) HelloController
@RestController
public class HelloController {
@Autowired
MethodService methodService;
@GetMapping("hello1")
public String hello1() {
return methodService.admin();
}
@GetMapping("hello2")
public String hello2() {
return methodService.user();
}
@GetMapping("hello3")
public String hello3() {
return methodService.hello();
}
}此時(shí)啟動(dòng)項(xiàng)目,我們用 admin 登錄,分別發(fā)送 hello1,hello2,hello3 請求

hello1 請求能夠訪問

因?yàn)榕渲昧?user() 方法要具有 user 權(quán)限才能訪問,所以報(bào) 403 錯(cuò)誤

總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Springboot中的異步任務(wù)執(zhí)行及監(jiān)控詳解
這篇文章主要介紹了Springboot中的異步任務(wù)執(zhí)行及監(jiān)控詳解,除了自己實(shí)現(xiàn)線程外,springboot本身就提供了通過注解的方式,進(jìn)行異步任務(wù)的執(zhí)行,下面主要記錄一下,在Springboot項(xiàng)目中實(shí)現(xiàn)異步任務(wù),以及對異步任務(wù)進(jìn)行封裝監(jiān)控,需要的朋友可以參考下2023-10-10
SpringBoot利用隨機(jī)鹽值實(shí)現(xiàn)密碼的加密與驗(yàn)證
這篇文章主要為大家詳細(xì)介紹了SpringBoot如何利用隨機(jī)鹽值實(shí)現(xiàn)密碼的加密與驗(yàn)證,文中的示例代碼講解詳細(xì),有需要的小伙伴可以參考下2024-02-02
Spring Boot 快速搭建微服務(wù)框架詳細(xì)教程
SpringBoot是為了簡化Spring應(yīng)用的創(chuàng)建、運(yùn)行、調(diào)試、部署等而出現(xiàn)的,使用它可以做到專注于Spring應(yīng)用的開發(fā),而無需過多關(guān)注XML的配置。本文重點(diǎn)給大家介紹Spring Boot 快速搭建微服務(wù)框架詳細(xì)教程,需要的的朋友參考下吧2017-09-09
SpringBoot項(xiàng)目修改訪問端口和訪問路徑的方法
這篇文章主要介紹了SpringBoot項(xiàng)目修改訪問端口和訪問路徑的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-12-12
Java使用Queryable-pageable實(shí)現(xiàn)分頁效果
這篇文章主要為大家介紹了Java如何使用Queryable-pageable從而實(shí)現(xiàn)分頁效果,文中的示例代碼簡潔易懂,感興趣的小伙伴可以動(dòng)手嘗試一下2022-06-06
js中去除字符串中所有的html標(biāo)簽代碼實(shí)例
這篇文章主要介紹了js中去除字符串中所有的html標(biāo)簽代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08
Java之使用POI教你玩轉(zhuǎn)Excel導(dǎo)入與導(dǎo)出
這篇文章主要介紹了Java之使用POI教你玩轉(zhuǎn)Excel導(dǎo)入與導(dǎo)出,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10
SpringBoot通過Nginx代理獲取真實(shí)IP
springboot作為后臺(tái)代碼,獲取到的登錄IP是前臺(tái)的代理服務(wù)器地址,并不是用戶的真實(shí)IP地址,本文主要介紹了SpringBoot通過Nginx代理獲取真實(shí)IP,具有一定的參考價(jià)值,感興趣的可以了解一下2024-01-01

