SpringBoot整合SpringSecurity實(shí)現(xiàn)認(rèn)證攔截的教程
一. SpringSecurity簡(jiǎn)介
1. SpringSecurity概述
Spring Security 是 Spring 社區(qū)的一個(gè)頂級(jí)項(xiàng)目,也是 Spring Boot 官方推薦使用的安全框架。
除了常規(guī)的認(rèn)證(Authentication)和授權(quán)(Authorization)之外,Spring Security還提供了諸如ACLs,LDAP,JAAS,CAS等高級(jí)特性以滿足復(fù)雜場(chǎng)景下的安全需求。
另外,就目前而言,Spring Security和Shiro也是當(dāng)前廣大應(yīng)用使用比較廣泛的兩個(gè)安全框架。
Spring Security 應(yīng)用級(jí)別的安全主要包含兩個(gè)主要部分,即登錄認(rèn)證(Authentication)和訪問(wèn)授權(quán)(Authorization),首先用戶登錄的時(shí)候傳入登錄信息,登錄驗(yàn)證器完成登錄認(rèn)證并將登錄認(rèn)證好的信息存儲(chǔ)到請(qǐng)求上下文,然后再進(jìn)行其他操作,如在進(jìn)行接口訪問(wèn)、方法調(diào)用時(shí),權(quán)限認(rèn)證器從上下文中獲取登錄認(rèn)證信息,然后根據(jù)認(rèn)證信息獲取權(quán)限信息,通過(guò)權(quán)限信息和特定的授權(quán)策略決定是否授權(quán)。
2. SpringSecurity的特征
- 對(duì)身份驗(yàn)證和授權(quán)的全面和可擴(kuò)展的支持;
- 防止會(huì)話固定,點(diǎn)擊劫持,跨站點(diǎn)請(qǐng)求偽造等攻擊;
- Servlet API集成;
- 可選與Spring Web MVC集成。
二. SpringBoot整合SpringSecurity實(shí)現(xiàn)步驟
1. 需求分析
當(dāng)用戶來(lái)訪問(wèn)接口時(shí),根據(jù)用戶攜帶的Authorization去查詢此用戶的角色,再根據(jù)設(shè)置好的角色所具有的權(quán)限進(jìn)行判斷,如果訪問(wèn)的接口是該角色下的接口,則進(jìn)行接口放行。
2. 創(chuàng)建web項(xiàng)目
我們按照之前的經(jīng)驗(yàn),創(chuàng)建一個(gè)web程序,并將之改造成Spring Boot項(xiàng)目,具體過(guò)程略。
3. 測(cè)試未添加SpringSecurity時(shí)的情況
我們可以先測(cè)試一下項(xiàng)目中不添加Spring Security依賴包的情況,在這種情況下,我直接創(chuàng)建一個(gè)Controller接口,然后啟動(dòng)項(xiàng)目進(jìn)行測(cè)試。
package com.yyg.boot.web; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; /** * @Author * @Date Created in 2020/5/18 * @Description Description */ @RestController public class IndexController { @GetMapping("/hello") public String hello() { return "Hello SpringSecurity!"; } }
4. 創(chuàng)建入口類
package com.yyg.boot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * @Author 一一哥Sun * @Date Created in 2020/5/18 * @Description Description */ @SpringBootApplication public class SecurityApplication { public static void main(String[] args){ SpringApplication.run(SecurityApplication.class,args); } }
5. 訪問(wèn)接口
此時(shí)我們可以看到,在瀏覽器中可以直接訪問(wèn)這個(gè)接口方法。
6. 添加Spring Security依賴包
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
7. 重啟項(xiàng)目測(cè)試
當(dāng)添加了spring-boot-starter-security依賴包之后,我們此時(shí)再重新啟動(dòng)項(xiàng)目進(jìn)行測(cè)試。此時(shí)會(huì)發(fā)現(xiàn)控制臺(tái)中有一行日志信息:也就是Spring Boot會(huì)自動(dòng)產(chǎn)生一個(gè)隨機(jī)的密碼。
然后我們?cè)僭L問(wèn)剛才的接口,會(huì)發(fā)現(xiàn)接口會(huì)自動(dòng)重定向到login登錄頁(yè)面。
然后在這個(gè)登錄頁(yè)面中,我們可以輸入用戶名和密碼:
- 用戶名:user
- 密碼:控制臺(tái)的隨機(jī)密碼
然后此時(shí)才可以看到剛才的接口內(nèi)容。
這是因?yàn)楫?dāng)Spring項(xiàng)目中引入了Spring Security依賴的時(shí)候,項(xiàng)目會(huì)默認(rèn)開(kāi)啟如下配置:
security.basic.enabled=true
這個(gè)配置開(kāi)啟了一個(gè)表單認(rèn)證,所有服務(wù)的訪問(wèn)都必須先過(guò)這個(gè)認(rèn)證,默認(rèn)的用戶名為user,密碼由Sping Security自動(dòng)生成,回到IDE的控制臺(tái),可以找到密碼信息:
Using generated security password: 078db2a5-ae07-4a10-a85c-cf0162a7e966
8. 修改登錄表單的用戶名和密碼
我們可以在application.yml文件中,通過(guò)spring.security屬性進(jìn)行用戶名和密碼的配置。
server: port: 8080 spring: security: user: name: admin password: 123
此時(shí)可以看到,新的登錄名和密碼變成了我們?cè)O(shè)置好的。
三. 基于HttpBasic認(rèn)證
1. HttpBasic認(rèn)證實(shí)現(xiàn)
配置SpringSecurity認(rèn)證方式。
創(chuàng)建一個(gè)配置類SpringSecurityConfig繼承org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter這個(gè)抽象類并重寫(xiě)configure(HttpSecurity http)方法。
WebSecurityConfigurerAdapter是由Spring Security提供的Web應(yīng)用安全配置的適配器:
@Configuration public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.httpBasic() // HttpBasic // http.formLogin() // 表單方式 .and() .authorizeRequests() // 授權(quán)配置 .anyRequest() // 所有請(qǐng)求 .authenticated(); // 都需要認(rèn)證 } }
HttpBasic登錄效果
2. HttpBasic基本原理
上面我們開(kāi)啟了一個(gè)最簡(jiǎn)單的Spring Security安全配置,下面我們來(lái)了解下Spring Security的基本原理。通過(guò)上面的的配置,代碼的執(zhí)行過(guò)程可以簡(jiǎn)化為下圖表示:
如上圖所示,Spring Security包含了眾多的過(guò)濾器,這些過(guò)濾器形成了一條鏈,所有請(qǐng)求都必須通過(guò)這些過(guò)濾器后才能成功訪問(wèn)到資源。
其中UsernamePasswordAuthenticationFilter過(guò)濾器用于處理基于表單方式的登錄認(rèn)證,而B(niǎo)asicAuthenticationFilter用于處理基于HTTP Basic方式的登錄驗(yàn)證,后面還可能包含一系列別的過(guò)濾器(可以通過(guò)相應(yīng)配置開(kāi)啟)。
在過(guò)濾器鏈的末尾是一個(gè)名為FilterSecurityInterceptor的攔截器,用于判斷當(dāng)前請(qǐng)求身份認(rèn)證是否成功,是否有相應(yīng)的權(quán)限,當(dāng)身份認(rèn)證失敗或者權(quán)限不足的時(shí)候便會(huì)拋出相應(yīng)的異常。ExceptionTranslateFilter捕獲并處理,所以我們?cè)贓xceptionTranslateFilter過(guò)濾器用于處理了FilterSecurityInterceptor拋出的異常并進(jìn)行處理,比如需要身份認(rèn)證時(shí)將請(qǐng)求重定向到相應(yīng)的認(rèn)證頁(yè)面,當(dāng)認(rèn)證失敗或者權(quán)限不足時(shí)返回相應(yīng)的提示信息。
四. SpringBoot集成SpringSecurity實(shí)現(xiàn)權(quán)限管理
我們?cè)谏厦姘咐幕A(chǔ)上,進(jìn)行本案例的開(kāi)發(fā)講解。
1. 創(chuàng)建實(shí)體類
1.1 創(chuàng)建Admin實(shí)體類
package com.yyg.boot.domain; import lombok.Data; import java.io.Serializable; /** * @Author 一一哥Sun * @Date Created in 2020/5/18 * @Description Description */ @Data public class Admin implements Serializable { private String username; private String password; }
1.2 創(chuàng)建Member實(shí)體類
package com.yyg.boot.domain; import lombok.Data; import java.io.Serializable; /** * @Author 一一哥Sun * @Date Created in 2020/5/18 * @Description Description */ @Data public class Member implements Serializable { private String id; private String username; private String password; }
2. 繼承WebSecurityConfigurerAdapter配置角色權(quán)限
package com.yyg.boot.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; /** * @Author 一一哥Sun * @Date Created in 2020/5/18 * @Description Description */ @Configuration public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { //@Override //protected void configure(HttpSecurity http) throws Exception { //http.httpBasic() // 簡(jiǎn)單的HttpBasic登錄方式 //http.formLogin() // 提供一個(gè)登錄的表單 //.and() //.authorizeRequests() // 授權(quán)配置 //.anyRequest() // 所有請(qǐng)求 //.authenticated(); // 都需要認(rèn)證 //} @Autowired private UserDetailsService userDetailsService; @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override public void configure(WebSecurity web) throws Exception { super.configure(web); } //內(nèi)存方式創(chuàng)建用戶 // @Override // public void configure(AuthenticationManagerBuilder auth) throws Exception { // auth.inMemoryAuthentication() // .withUser("admin").password("123456").roles("ADMIN") // .and() // .withUser("member").password("123456").roles("MEMBER"); // } @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService) //passwordEncoder是對(duì)密碼的加密處理,如果user中密碼沒(méi)有加密,則可以不加此方法。注意加密請(qǐng)使用security自帶的加密方式。 .passwordEncoder(passwordEncoder()); } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf() //禁用了 csrf 功能 .disable() //限定簽名成功的請(qǐng)求 .authorizeRequests() .antMatchers("/employee/*") //對(duì)employee 下的接口,需要 MEMBER 或者 ADMIN 權(quán)限 .hasAnyRole("MEMBER","ADMIN") //對(duì)employee/login接口直接放行,不限制 .antMatchers("/employee/login") .permitAll() //對(duì)admin下的接口 需要ADMIN權(quán)限 .antMatchers("/admin/**") .hasRole("ADMIN") //不攔截 oauth 開(kāi)放的資源 .antMatchers("/oauth/**") .permitAll() //其他沒(méi)有限定的請(qǐng)求,允許訪問(wèn) .anyRequest() .permitAll() .and() //對(duì)于沒(méi)有配置權(quán)限的其他請(qǐng)求允許匿名訪問(wèn) .anonymous() .and() //使用 spring security 默認(rèn)登錄頁(yè)面 .formLogin() .and() //啟用http 基礎(chǔ)驗(yàn)證 .httpBasic(); } }
3. 創(chuàng)建UserDetailsService
package com.yyg.boot.service; import com.yyg.boot.domain.Admin; import com.yyg.boot.domain.Member; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; /** * @Author * @Date Created in 2020/5/18 * @Description Description */ @Service public class UserDetailServiceImpl implements UserDetailsService { @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { List<GrantedAuthority> grantedAuthorities = new ArrayList<>(); //生成環(huán)境是查詢數(shù)據(jù)庫(kù)獲取username的角色用于后續(xù)權(quán)限判斷(如:張三 admin) //這里不做數(shù)據(jù)庫(kù)操作,給定假數(shù)據(jù),進(jìn)行簡(jiǎn)單模擬. if ("member".equals(username)) { Member member = new Member(); member.setUsername("member"); member.setPassword("123456"); GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_MEMBER"); grantedAuthorities.add(grantedAuthority); //創(chuàng)建一個(gè)用戶,用于判斷權(quán)限,請(qǐng)注意此用戶名和方法參數(shù)中的username一致;BCryptPasswordEncoder是用來(lái)演示加密使用。 return new User(member.getUsername(), new BCryptPasswordEncoder().encode(member.getPassword()), grantedAuthorities); } if ("admin".equals(username)) { Admin admin = new Admin(); admin.setUsername("admin"); admin.setPassword("123456"); GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_ADMIN"); grantedAuthorities.add(grantedAuthority); return new User(admin.getUsername(), new BCryptPasswordEncoder().encode(admin.getPassword()), grantedAuthorities); } else { return null; } } }
4. 創(chuàng)建controller層代碼
4.1 創(chuàng)建AdminController
package com.yyg.boot.web; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @Author 一一哥Sun * @Date Created in 2020/5/18 * @Description Description */ @RestController @RequestMapping("/admin") public class AdminController { @GetMapping("/greeting") public String greeting() { return "Hello,Admin!"; } @GetMapping("/login") public String login() { return "login success!"; } }
4.2 創(chuàng)建MemberController
package com.yyg.boot.web; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @Author 一一哥Sun * @Date Created in 2020/5/18 * @Description Description */ @RestController @RequestMapping("/member") public class MemberController { @GetMapping("/greeting") public String greeting() { return "Hello,Member!"; } @GetMapping("/login") public String login() { return "login success!"; } }
5. 進(jìn)行測(cè)試
此時(shí)我們可以利用postman,通過(guò)Basic認(rèn)證方式,攜帶用戶名和密碼進(jìn)行相關(guān)接口的訪問(wèn)。
5.1 member身份的權(quán)限,只能訪問(wèn)member相關(guān)的接口:
5.2 admin身份的權(quán)限,可以訪問(wèn)admin與member相關(guān)的接口:
后續(xù)我們可以關(guān)聯(lián)數(shù)據(jù)庫(kù),從數(shù)據(jù)庫(kù)中查詢用戶的身份和角色信息,從而進(jìn)一步給用戶分配權(quán)限信息。
結(jié)語(yǔ)
至此,我們就對(duì)Web項(xiàng)目添加了一個(gè)安全防護(hù),而且實(shí)現(xiàn)起來(lái)簡(jiǎn)直不要太easy!現(xiàn)在你知道該怎么保護(hù)自己的Web項(xiàng)目不被“傷害”了嗎?
以上就是SpringBoot整合SpringSecurity實(shí)現(xiàn)認(rèn)證攔截的教程的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot整合SpringSecurity實(shí)現(xiàn)認(rèn)證攔截的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- SpringSecurity自定義資源攔截規(guī)則及登錄界面跳轉(zhuǎn)問(wèn)題
- SpringSecurity攔截器鏈的使用詳解
- springsecurity實(shí)現(xiàn)攔截器的使用示例
- Swagger2不被SpringSecurity框架攔截的配置及說(shuō)明
- Spring Boot security 默認(rèn)攔截靜態(tài)資源的解決方法
- SpringSecurity實(shí)現(xiàn)動(dòng)態(tài)url攔截(基于rbac模型)
- Spring Security攔截器引起Java CORS跨域失敗的問(wèn)題及解決
- SpringBoot+SpringSecurity 不攔截靜態(tài)資源的實(shí)現(xiàn)
- 淺談Spring Security 對(duì)于靜態(tài)資源的攔截與放行
- spring Security配置攔截規(guī)則小結(jié)
相關(guān)文章
如何解決java.util.zip.ZipFile解壓后被java占用問(wèn)題
這篇文章主要介紹了如何解決java.util.zip.ZipFile解壓后被java占用問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06Spring Task定時(shí)任務(wù)的配置和使用詳解
本篇文章主要介紹了Spring Task定時(shí)任務(wù)的配置和使用詳解,實(shí)例分析了Spring Task定時(shí)任務(wù)的配置和使用的技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-04-04完整B樹(shù)算法Java實(shí)現(xiàn)代碼
這篇文章主要為大家詳細(xì)介紹了完整的B樹(shù)算法Java實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09詳解Java如何通過(guò)Socket實(shí)現(xiàn)查詢IP
在本文中,我們來(lái)學(xué)習(xí)下如何找到連接到服務(wù)器的客戶端計(jì)算機(jī)的IP地址。我們將創(chuàng)建一個(gè)簡(jiǎn)單的客戶端-服務(wù)器場(chǎng)景,讓我們探索用于TCP/IP通信的java.net?API,感興趣的可以了解一下2022-10-10