SpringBoot整合SpringSecurity實現認證攔截的教程
一. SpringSecurity簡介
1. SpringSecurity概述
Spring Security 是 Spring 社區(qū)的一個頂級項目,也是 Spring Boot 官方推薦使用的安全框架。
除了常規(guī)的認證(Authentication)和授權(Authorization)之外,Spring Security還提供了諸如ACLs,LDAP,JAAS,CAS等高級特性以滿足復雜場景下的安全需求。
另外,就目前而言,Spring Security和Shiro也是當前廣大應用使用比較廣泛的兩個安全框架。
Spring Security 應用級別的安全主要包含兩個主要部分,即登錄認證(Authentication)和訪問授權(Authorization),首先用戶登錄的時候傳入登錄信息,登錄驗證器完成登錄認證并將登錄認證好的信息存儲到請求上下文,然后再進行其他操作,如在進行接口訪問、方法調用時,權限認證器從上下文中獲取登錄認證信息,然后根據認證信息獲取權限信息,通過權限信息和特定的授權策略決定是否授權。
2. SpringSecurity的特征
- 對身份驗證和授權的全面和可擴展的支持;
- 防止會話固定,點擊劫持,跨站點請求偽造等攻擊;
- Servlet API集成;
- 可選與Spring Web MVC集成。
二. SpringBoot整合SpringSecurity實現步驟
1. 需求分析
當用戶來訪問接口時,根據用戶攜帶的Authorization去查詢此用戶的角色,再根據設置好的角色所具有的權限進行判斷,如果訪問的接口是該角色下的接口,則進行接口放行。
2. 創(chuàng)建web項目
我們按照之前的經驗,創(chuàng)建一個web程序,并將之改造成Spring Boot項目,具體過程略。
3. 測試未添加SpringSecurity時的情況
我們可以先測試一下項目中不添加Spring Security依賴包的情況,在這種情況下,我直接創(chuàng)建一個Controller接口,然后啟動項目進行測試。
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. 訪問接口
此時我們可以看到,在瀏覽器中可以直接訪問這個接口方法。
6. 添加Spring Security依賴包
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
7. 重啟項目測試
當添加了spring-boot-starter-security依賴包之后,我們此時再重新啟動項目進行測試。此時會發(fā)現控制臺中有一行日志信息:也就是Spring Boot會自動產生一個隨機的密碼。
然后我們再訪問剛才的接口,會發(fā)現接口會自動重定向到login登錄頁面。
然后在這個登錄頁面中,我們可以輸入用戶名和密碼:
- 用戶名:user
- 密碼:控制臺的隨機密碼
然后此時才可以看到剛才的接口內容。
這是因為當Spring項目中引入了Spring Security依賴的時候,項目會默認開啟如下配置:
security.basic.enabled=true
這個配置開啟了一個表單認證,所有服務的訪問都必須先過這個認證,默認的用戶名為user,密碼由Sping Security自動生成,回到IDE的控制臺,可以找到密碼信息:
Using generated security password: 078db2a5-ae07-4a10-a85c-cf0162a7e966
8. 修改登錄表單的用戶名和密碼
我們可以在application.yml文件中,通過spring.security屬性進行用戶名和密碼的配置。
server: port: 8080 spring: security: user: name: admin password: 123
此時可以看到,新的登錄名和密碼變成了我們設置好的。
三. 基于HttpBasic認證
1. HttpBasic認證實現
配置SpringSecurity認證方式。
創(chuàng)建一個配置類SpringSecurityConfig繼承org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter這個抽象類并重寫configure(HttpSecurity http)方法。
WebSecurityConfigurerAdapter是由Spring Security提供的Web應用安全配置的適配器:
@Configuration public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.httpBasic() // HttpBasic // http.formLogin() // 表單方式 .and() .authorizeRequests() // 授權配置 .anyRequest() // 所有請求 .authenticated(); // 都需要認證 } }
HttpBasic登錄效果
2. HttpBasic基本原理
上面我們開啟了一個最簡單的Spring Security安全配置,下面我們來了解下Spring Security的基本原理。通過上面的的配置,代碼的執(zhí)行過程可以簡化為下圖表示:
如上圖所示,Spring Security包含了眾多的過濾器,這些過濾器形成了一條鏈,所有請求都必須通過這些過濾器后才能成功訪問到資源。
其中UsernamePasswordAuthenticationFilter過濾器用于處理基于表單方式的登錄認證,而BasicAuthenticationFilter用于處理基于HTTP Basic方式的登錄驗證,后面還可能包含一系列別的過濾器(可以通過相應配置開啟)。
在過濾器鏈的末尾是一個名為FilterSecurityInterceptor的攔截器,用于判斷當前請求身份認證是否成功,是否有相應的權限,當身份認證失敗或者權限不足的時候便會拋出相應的異常。ExceptionTranslateFilter捕獲并處理,所以我們在ExceptionTranslateFilter過濾器用于處理了FilterSecurityInterceptor拋出的異常并進行處理,比如需要身份認證時將請求重定向到相應的認證頁面,當認證失敗或者權限不足時返回相應的提示信息。
四. SpringBoot集成SpringSecurity實現權限管理
我們在上面案例的基礎上,進行本案例的開發(fā)講解。
1. 創(chuàng)建實體類
1.1 創(chuàng)建Admin實體類
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實體類
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配置角色權限
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() // 簡單的HttpBasic登錄方式 //http.formLogin() // 提供一個登錄的表單 //.and() //.authorizeRequests() // 授權配置 //.anyRequest() // 所有請求 //.authenticated(); // 都需要認證 //} @Autowired private UserDetailsService userDetailsService; @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override public void configure(WebSecurity web) throws Exception { super.configure(web); } //內存方式創(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是對密碼的加密處理,如果user中密碼沒有加密,則可以不加此方法。注意加密請使用security自帶的加密方式。 .passwordEncoder(passwordEncoder()); } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf() //禁用了 csrf 功能 .disable() //限定簽名成功的請求 .authorizeRequests() .antMatchers("/employee/*") //對employee 下的接口,需要 MEMBER 或者 ADMIN 權限 .hasAnyRole("MEMBER","ADMIN") //對employee/login接口直接放行,不限制 .antMatchers("/employee/login") .permitAll() //對admin下的接口 需要ADMIN權限 .antMatchers("/admin/**") .hasRole("ADMIN") //不攔截 oauth 開放的資源 .antMatchers("/oauth/**") .permitAll() //其他沒有限定的請求,允許訪問 .anyRequest() .permitAll() .and() //對于沒有配置權限的其他請求允許匿名訪問 .anonymous() .and() //使用 spring security 默認登錄頁面 .formLogin() .and() //啟用http 基礎驗證 .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)境是查詢數據庫獲取username的角色用于后續(xù)權限判斷(如:張三 admin) //這里不做數據庫操作,給定假數據,進行簡單模擬. 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)建一個用戶,用于判斷權限,請注意此用戶名和方法參數中的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. 進行測試
此時我們可以利用postman,通過Basic認證方式,攜帶用戶名和密碼進行相關接口的訪問。
5.1 member身份的權限,只能訪問member相關的接口:
5.2 admin身份的權限,可以訪問admin與member相關的接口:
后續(xù)我們可以關聯數據庫,從數據庫中查詢用戶的身份和角色信息,從而進一步給用戶分配權限信息。
結語
至此,我們就對Web項目添加了一個安全防護,而且實現起來簡直不要太easy!現在你知道該怎么保護自己的Web項目不被“傷害”了嗎?
以上就是SpringBoot整合SpringSecurity實現認證攔截的教程的詳細內容,更多關于SpringBoot整合SpringSecurity實現認證攔截的資料請關注腳本之家其它相關文章!
- Springboot集成Spring Security實現JWT認證的步驟詳解
- SpringBoot集成Spring security JWT實現接口權限認證
- SpringBoot+SpringSecurity實現基于真實數據的授權認證
- springboot+springsecurity如何實現動態(tài)url細粒度權限認證
- SpringBoot整合SpringSecurity實現JWT認證的項目實踐
- SpringBoot+SpringSecurity+JWT實現系統(tǒng)認證與授權示例
- SpringBoot security安全認證登錄的實現方法
- SpringBoot整合SpringSecurity和JWT和Redis實現統(tǒng)一鑒權認證
- SpringBoot+Spring Security基于內存用戶認證的實現
相關文章
java 實現反射 json動態(tài)轉實體類--fastjson
這篇文章主要介紹了java 實現反射 json動態(tài)轉實體類--fastjson,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02spring @Profiles和@PropertySource實現根據環(huán)境切換配置文件
這篇文章主要介紹了spring @Profiles和@PropertySource根據環(huán)境切換配置文件,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11Java 多線程Synchronized和Lock的區(qū)別
這篇文章主要介紹了Java 多線程Synchronized和Lock的區(qū)別,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2021-01-01