【SpringSecurity】01 授權、認證、登出
【前提情要】
Security學習地址:
https://www.bilibili.com/video/BV1KE411i7bC
狂神的微信筆記:
https://mp.weixin.qq.com/s?__biz=Mzg2NTAzMTExNg==&mid=2247483957&idx=1&sn=fc30511490b160cd1519e7a7ee3d4ed0&chksm=ce610496f9168d8082bf6cb2e54b0b8628a1db596c1d297d06e756e621569dc3047334b3062c&mpshare=1&scene=23&srcid=0729Qvgf1Lb6AstEnrABaRiH&sharer_sharetime=1595987265426&sharer_shareid=04a2988e19defb0bbbb3d27a02ec4289#rd
【演示案例搭建】
首先是新建一個SpringBoot工程,
不要勾選任何元件,直接新增依賴即可:
<dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring5</artifactId> </dependency> <dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-java8time</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
把靜態資原始檔和配置匯入資源目錄中:
每個Level目錄中的頁面都一樣的【空的,啥都沒有】,只是為了代表不同的可訪問級別的資源
首頁展示了所有可以訪問的內容:
然後這是登陸頁面:
編寫一個路由控制器,實現頁面之間的跳轉訪問:
package cn.echo42.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; /** * @author DaiZhiZhou * @file SpringSecurity * @create 2020-07-29 9:53 */ @Controller public class RouterController { @RequestMapping({"/","/index"}) public String index(){ return "index"; } @RequestMapping("/toLogin") public String toLogin(){ return "views/login"; } @RequestMapping("/level1/{id}") public String level1(@PathVariable("id") int id){ return "views/level1/" + id; } @RequestMapping("/level2/{id}") public String level2(@PathVariable("id") int id){ return "views/level2/" + id; } @RequestMapping("/level3/{id}") public String level3(@PathVariable("id") int id){ return "views/level3/" + id; } }
在我們啟動工程之後,所有的頁面毫無阻攔的就可以被所有的訪問者訪問到
使用者的隱私資料就可以被攻擊者竊取。簡而言之就是安全隱患
從這裡引入安全的概念,然後就是SpringSecurity這樣一個解決方案:
Spring Security是一個功能強大且高度可定製的身份驗證和訪問控制框架。
它實際上是保護基於spring的應用程式的標準。
Spring Security是一個框架,側重於為Java應用程式提供身份驗證和授權。
與所有Spring專案一樣,Spring安全性的真正強大之處在於它可以輕鬆地擴充套件以滿足定製需求
從官網的介紹中可以知道這是一個許可權框架。
想我們之前做專案是沒有使用框架是怎麼控制權限的?
對於許可權 一般會細分為功能許可權,訪問許可權,和選單許可權。
程式碼會寫的非常的繁瑣,冗餘。
怎麼解決之前寫許可權程式碼繁瑣,冗餘的問題,
一些主流框架就應運而生而Spring Scecurity就是其中的一種。
首先引入安全框架元件座標:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
我們之前編寫的內容不需要做出任何的改動:
【授權authorize】
編寫一個SpringSecurity配置類:
package cn.echo42.config; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; /** * @author DaiZhiZhou * @file SpringSecurity * @create 2020-07-29 10:34 */ @EnableWebSecurity // 註冊為WebSecurity的一個Bean public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Override // 注意重寫的是這個HttpSecurity引數的configure方法 protected void configure(HttpSecurity http) throws Exception { // 首頁允許所有人訪問,那些LEVEL頁面只有對應具備的許可權的使用者才可以訪問 http. authorizeRequests(). // 對以下請求進行授權 antMatchers("/"). // /表示我們的首頁 permitAll(). // 表示完全允許訪問 // 對相應的地址進行相應的角色設定 antMatchers("/level1/**").hasRole("vip1"). antMatchers("/level2/**").hasRole("vip2"). antMatchers("/level3/**").hasRole("vip3"); } }
這時候執行工程:
雖然首頁所有人均可以訪問,但是點選下面的這些LEVEL頁面就會被拒絕
There was an unexpected error (type=Forbidden, status=403).
訪問被禁止了,也就是我們Security起效了
但是如果訪問禁止,按照業務流程,我們應該是將這個請求返回到登入頁面:
所以需要進行下一步的設定:
// 沒有許可權,重定向到登入頁面 http.formLogin();
這時候再來訪問就會跳轉到登入頁面:
不過這登陸頁面並不是我們自己那個素材的登入頁,而是Security提供的
【許可權認證】
重寫 過載的config方法,是引數為AuthenticationManagerBuilder的方法
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { super.configure(auth); }
但是我們這個案例沒有涉及資料庫,所以使用的是從記憶體中獲取資料用以認證
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication(). // 認證角色 使用者名稱稱、密碼、對應的多個角色 // 超級管理員就直接賦值所有角色即可 withUser("admin").password("admin").roles("vip1","vip2","vip3"). // 如果是多個角色則使用and方法加上 and().withUser("user1").password("123").roles("vip1"). and().withUser("user2").password("123").roles("vip2"). and().withUser("user3").password("123").roles("vip3"); }
然後再次訪問:
當訪問被拒絕重定向到登入頁面
然後輸入我們在Security設定的許可權資訊之後。。。
我這裡看不出來,只有一個500,Security的要求意思是說,密碼沒有加密也不能訪問
所以我們需要做的是就是對密碼再加密即可:
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()). // 認證角色 使用者名稱稱、密碼、對應的多個角色 // 超級管理員就直接賦值所有角色即可 withUser("admin").password(new BCryptPasswordEncoder().encode("admin")).roles("vip1","vip2","vip3"). // 如果是多個角色則使用and方法加上 and().withUser("user1").password(new BCryptPasswordEncoder().encode("123")).roles("vip1"). and().withUser("user2").password(new BCryptPasswordEncoder().encode("123")).roles("vip2"). and().withUser("user3").password(new BCryptPasswordEncoder().encode("123")).roles("vip3"); }
再次訪問:
使用user1訪問level1目錄的資源是可以的
但是訪問level2就沒辦法了
【登出功能】
@Override // 注意重寫的是這個HttpSecurity引數的configure方法 protected void configure(HttpSecurity http) throws Exception { // 首頁允許所有人訪問,那些LEVEL頁面只有對應具備的許可權的使用者才可以訪問 http. authorizeRequests(). // 對以下請求進行授權 antMatchers("/"). // /表示我們的首頁 permitAll(). // 表示完全允許訪問 // 對相應的地址進行相應的角色設定 antMatchers("/level1/**").hasRole("vip1"). antMatchers("/level2/**").hasRole("vip2"). antMatchers("/level3/**").hasRole("vip3"); // 沒有許可權,重定向到登入頁面 http.formLogin(); // 登出,退出 http.logout(); }
在首頁中插入一個登出標籤:
<a class="item" th:href="@{/logout}"> <i class="sign-out icon"></i> 登出 </a>
測試退出:
點選之後自動回到登入頁面,並且標註了是登出回到登入頁的
如果不是跳轉到登入頁,而是首頁,則可以:
http.logout().logoutSuccessUrl("/");
即追加一個登出成功的重定向地址