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)和訪問授權(quán)(Authorization),首先用戶登錄的時(shí)候傳入登錄信息,登錄驗(yàn)證器完成登錄認(rèn)證并將登錄認(rèn)證好的信息存儲(chǔ)到請(qǐng)求上下文,然后再進(jìn)行其他操作,如在進(jìn)行接口訪問、方法調(diào)用時(shí),權(quán)限認(rèn)證器從上下文中獲取登錄認(rèn)證信息,然后根據(jù)認(rèn)證信息獲取權(quán)限信息,通過權(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)用戶來訪問接口時(shí),根據(jù)用戶攜帶的Authorization去查詢此用戶的角色,再根據(jù)設(shè)置好的角色所具有的權(quán)限進(jìn)行判斷,如果訪問的接口是該角色下的接口,則進(jìn)行接口放行。
2. 創(chuàng)建web項(xiàng)目
我們按照之前的經(jīng)驗(yàn),創(chuàng)建一個(gè)web程序,并將之改造成Spring Boot項(xiàng)目,具體過程略。
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. 訪問接口
此時(shí)我們可以看到,在瀏覽器中可以直接訪問這個(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問剛才的接口,會(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)開啟如下配置:
security.basic.enabled=true
這個(gè)配置開啟了一個(gè)表單認(rèn)證,所有服務(wù)的訪問都必須先過這個(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文件中,通過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è)抽象類并重寫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基本原理
上面我們開啟了一個(gè)最簡(jiǎn)單的Spring Security安全配置,下面我們來了解下Spring Security的基本原理。通過上面的的配置,代碼的執(zhí)行過程可以簡(jiǎn)化為下圖表示:
如上圖所示,Spring Security包含了眾多的過濾器,這些過濾器形成了一條鏈,所有請(qǐng)求都必須通過這些過濾器后才能成功訪問到資源。
其中UsernamePasswordAuthenticationFilter過濾器用于處理基于表單方式的登錄認(rèn)證,而BasicAuthenticationFilter用于處理基于HTTP Basic方式的登錄驗(yàn)證,后面還可能包含一系列別的過濾器(可以通過相應(yīng)配置開啟)。
在過濾器鏈的末尾是一個(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過濾器用于處理了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)行本案例的開發(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中密碼沒有加密,則可以不加此方法。注意加密請(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 開放的資源 .antMatchers("/oauth/**") .permitAll() //其他沒有限定的請(qǐng)求,允許訪問 .anyRequest() .permitAll() .and() //對(duì)于沒有配置權(quán)限的其他請(qǐng)求允許匿名訪問 .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是用來演示加密使用。 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,通過Basic認(rèn)證方式,攜帶用戶名和密碼進(jìn)行相關(guān)接口的訪問。
5.1 member身份的權(quán)限,只能訪問member相關(guān)的接口:
5.2 admin身份的權(quán)限,可以訪問admin與member相關(guān)的接口:
后續(xù)我們可以關(guān)聯(lián)數(shù)據(jù)庫(kù),從數(shù)據(jù)庫(kù)中查詢用戶的身份和角色信息,從而進(jìn)一步給用戶分配權(quán)限信息。
結(jié)語
至此,我們就對(duì)Web項(xiàng)目添加了一個(gè)安全防護(hù),而且實(shí)現(xiàn)起來簡(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)文章!
- Springboot集成Spring Security實(shí)現(xiàn)JWT認(rèn)證的步驟詳解
- SpringBoot集成Spring security JWT實(shí)現(xiàn)接口權(quán)限認(rèn)證
- SpringBoot+SpringSecurity實(shí)現(xiàn)基于真實(shí)數(shù)據(jù)的授權(quán)認(rèn)證
- springboot+springsecurity如何實(shí)現(xiàn)動(dòng)態(tài)url細(xì)粒度權(quán)限認(rèn)證
- SpringBoot整合SpringSecurity實(shí)現(xiàn)JWT認(rèn)證的項(xiàng)目實(shí)踐
- SpringBoot+SpringSecurity+JWT實(shí)現(xiàn)系統(tǒng)認(rèn)證與授權(quán)示例
- SpringBoot security安全認(rèn)證登錄的實(shí)現(xiàn)方法
- SpringBoot整合SpringSecurity和JWT和Redis實(shí)現(xiàn)統(tǒng)一鑒權(quán)認(rèn)證
- SpringBoot+Spring Security基于內(nèi)存用戶認(rèn)證的實(shí)現(xiàn)
相關(guān)文章
java 實(shí)現(xiàn)反射 json動(dòng)態(tài)轉(zhuǎn)實(shí)體類--fastjson
這篇文章主要介紹了java 實(shí)現(xiàn)反射 json動(dòng)態(tài)轉(zhuǎn)實(shí)體類--fastjson,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-02-02spring @Profiles和@PropertySource實(shí)現(xiàn)根據(jù)環(huán)境切換配置文件
這篇文章主要介紹了spring @Profiles和@PropertySource根據(jù)環(huán)境切換配置文件,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11使用Java實(shí)現(xiàn)2048小游戲代碼實(shí)例
這篇文章主要介紹了使用Java實(shí)現(xiàn)2048小游戲代碼實(shí)例,2048 游戲是一款益智類游戲,玩家需要通過合并相同數(shù)字的方塊,不斷合成更大的數(shù)字,最終達(dá)到2048,游戲規(guī)則簡(jiǎn)單,但挑戰(zhàn)性很高,需要玩家靈活運(yùn)用策略和計(jì)算能力,本文將使用Java代碼實(shí)現(xiàn),需要的朋友可以參考下2023-10-10java接入創(chuàng)藍(lán)253短信驗(yàn)證碼的實(shí)例講解
下面小編就為大家分享一篇java接入創(chuàng)藍(lán)253短信驗(yàn)證碼的實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-01-01使用eclipse創(chuàng)建java項(xiàng)目的方法
這篇文章主要為大家詳細(xì)介紹了使用eclipse創(chuàng)建java項(xiàng)目的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-04-04Java 多線程Synchronized和Lock的區(qū)別
這篇文章主要介紹了Java 多線程Synchronized和Lock的區(qū)別,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2021-01-01SpringBoot 利用thymeleaf自定義錯(cuò)誤頁(yè)面
這篇文章主要介紹了SpringBoot 利用thymeleaf自定義錯(cuò)誤頁(yè)面,幫助大家更好的理解和使用springboot 框架,感興趣的朋友可以了解下2020-11-11