SpringBoot基于SpringSecurity表單登錄和權(quán)限驗(yàn)證的示例
一、簡介
上篇介紹了一個(gè)自己做的管理系統(tǒng),最近空閑的時(shí)間自己在繼續(xù)做,把之前登錄時(shí)候自定義的攔截器過濾器換成了基于SpringSecurity來做,其中遇到了很多坑,總結(jié)下,大家有遇到類似問題的話就當(dāng)是為大家閉坑吧。
二、項(xiàng)目實(shí)現(xiàn)功能和成果展示
首先來看下登錄界面:這是我輸入的一個(gè)正確的信息,點(diǎn)擊登錄后SpringSecurity會(huì)根據(jù)你輸入的用戶名和密碼去驗(yàn)證是否正確,如果正確的話就去你定義的頁面,我這里定義的是查詢教師信息頁面。來看下代碼吧。

三、準(zhǔn)備工作(前臺(tái)頁面、實(shí)體類)
實(shí)體類Teacher:字段主要有id、name、sex、email、schedule_Id、password、phone,上面都加了Hibernate的驗(yàn)證,其他字段大家可以自己寫,然后生成getter和setter方法

再來看下前臺(tái)頁面,前臺(tái)我使用的是一個(gè)BootStrap的頁面,模板語言使用的是Thymeleaf,當(dāng)然為了能夠在頁面支持security的語法需要在上面加入一個(gè)security的引入標(biāo)簽
index.html"頁面

index.html中登錄信息:需要注意的是我的表單是提交到/teacher/login這個(gè)路由上,然后就是字段中的name屬性必須要和你Teacher實(shí)體類中的字段名一致,不然頁面數(shù)據(jù)傳不到后臺(tái)。這里只截圖2個(gè)字段吧太長了其他的字段都一樣該好名字就行

然后我們再來看下TeacherController中的代碼:

這里面的代碼是我之前沒使用SpringSecurity的時(shí)候?qū)懙模F(xiàn)在注釋掉了,當(dāng)我們登錄成功之后就會(huì)到/query這個(gè)路由下的方法去執(zhí)行,也就是執(zhí)行查詢教師信息,先不看query方法,我們現(xiàn)在先來對接SpringSecurity,讓它先幫我們來進(jìn)行index中用戶名和密碼的登錄驗(yàn)證,然后再看query方法
四、使用SpringSecurity進(jìn)行表單驗(yàn)證登錄
要想使用SpringSecurity就需要現(xiàn)在pom.xml中加入SpringSecurity的依賴,你可以指定版本號(hào)也可以不指定,我這里沒有指定

注意:當(dāng)你引入SpringSecurity之后當(dāng)你再次去啟動(dòng)項(xiàng)目的時(shí)候,SpringSecurity自動(dòng)會(huì)給你跳到一個(gè)對話框,讓你輸入賬號(hào)和密碼,這里的用戶名是user,密碼在你啟動(dòng)的時(shí)候它會(huì)有一個(gè)加密的密文,你只需要復(fù)制進(jìn)去就可以登錄。
接下來我們要想實(shí)現(xiàn)自定義的表單驗(yàn)證登錄和其他高級功能就需要使用配置類來配置,在SpringBoot中新建一個(gè)配置類,讓它來繼承WebSecurityConfigurerAdapter,然后重寫里面的configure方法,在里面定義我們的邏輯,來看下代碼吧:

上面的是我項(xiàng)目中的配置,有些是本文用不到的,分別解釋下:從開始來說,http.formLogin的作用是使用form表單進(jìn)行登錄,也就是我們的index頁面。當(dāng)然你也可以使用Batic登錄,就是之前說的默認(rèn)給你的登錄信息界面。

上面的URL是我們的index頁面的數(shù)據(jù)也就是登錄的字段數(shù)據(jù),當(dāng)時(shí)我們提交的路徑是/teacher/login,而我們這里的配置意味著讓SpringSecurity去處理我們index表單數(shù)據(jù),你這樣寫SpringSecurity就知道對這個(gè)路徑進(jìn)行登錄驗(yàn)證處理。
請注意下面的代碼因?yàn)橛锌樱?/strong>
![]()
可以看到我這邊配置了2個(gè)Mathchers,如果不配置的話會(huì)出現(xiàn)什么狀況呢?你可能會(huì)遇到下面的這種錯(cuò)誤

什么意思呢?我先來簡化出來一個(gè)簡單的配置,下面的這段配置的意思:處理登錄的Url為/teacher/login,對任何的請求都進(jìn)行驗(yàn)證,下面的csrf先忽略,那么上面的定向次數(shù)太多是怎么來的呢?當(dāng)你點(diǎn)擊登錄之后,SpringSecurity會(huì)去處理/teacher/login這個(gè)請求,然后它發(fā)現(xiàn)這個(gè)請求也是需要驗(yàn)證的,于是乎就進(jìn)入了死循環(huán),它一直在驗(yàn)證。。。

要想解決這個(gè)問題,其實(shí)也很簡單,就是給它弄一個(gè)匹配器,告訴SpringSecurity,我在訪問這個(gè)路徑的時(shí)候你要放行不要攔截,比如說你可以這么寫:.antMatchers("/teacher/login").permitAll(),有的朋友可能看了我上面的代碼,你并不是這么寫的啊,你沒有對/teacher/login放行??!還記得我上面說的嗎在們登錄成功之后也就是/teacher/login驗(yàn)證之后是要去執(zhí)行/query方法去查詢教師信息的,因此我的匹配器匹配的是/query,所以我這么寫.antMatchers("/query").hasAnyRole("admin","stu")的時(shí)候并沒有permitAll,是因?yàn)楹竺娴膆asRole,表示看你當(dāng)前登錄的用戶有沒有admin或者是stu這樣的角色,有的話我就放行沒有的話就不放行,有的朋友可能會(huì)說那怎么角色該在哪里定義呢?下面我來看一下
五、角色匹配
這個(gè)時(shí)候我們需要重寫Adapter的另外一個(gè)configure方法注意這個(gè)方法的參數(shù)類型是AuthenticationManagerBuilder,它是一個(gè)認(rèn)證管理構(gòu)建器,可以幫我們構(gòu)建出你要對什么東西進(jìn)行認(rèn)證,比如角色、用戶、密碼,我們先來寫一個(gè)內(nèi)存認(rèn)證,后臺(tái)會(huì)說怎么連數(shù)據(jù)庫去認(rèn)證權(quán)限

上面這段代碼的意思是:我的認(rèn)證用戶為安安,密碼為:123123,安安的角色是admin,只有這些信息正確之后我才讓你認(rèn)證成功,去執(zhí)行下面的邏輯。我們來看下演示:


這就是代表登錄成功了,至于上面的角色顯示什么的我都會(huì)說到,那么我們來換一個(gè),剛才/query中的hasRole里面是admin和stu,我把a(bǔ)dmin去掉看下能登錄成功嗎?需要有一個(gè)stu的角色才能在登錄成功之后查看信息,而我們現(xiàn)在的用戶名和密碼都正確的情況下,角色不正確能夠成功嗎?


可以看到即使是使用了上面正確的用戶名和密碼登錄,但是提示沒有權(quán)限,這個(gè)頁面是我自定義的錯(cuò)誤頁面,你的可能會(huì)提示403沒有這些樣式。
六、從數(shù)據(jù)庫中讀取角色來驗(yàn)證
在真實(shí)的開發(fā)中,我們肯定是不會(huì)將用戶信息這種東西放到內(nèi)存中去的,肯定時(shí)從數(shù)據(jù)庫中讀取的,我在數(shù)據(jù)庫中新建了一張表,教師角色表,我們就從這張表讀取角色信息然后交給SpringSecurity去判斷角色

實(shí)體類這里就不截圖了,然后我們在TeacherRoleRepository中有這么一個(gè)方法,就是根據(jù)TeacherId去查詢教師的角色,為了方便我這里就不去新建什么Service了,直接就TeacherRoleRepository調(diào)用里面的findByTeacherId()方法
接下來,我們編寫一個(gè)TeacherDetailsService它實(shí)現(xiàn)一個(gè)UserDetailsService接口,UserDetailsService里面只有一個(gè)方法就是loadUserByUsername(String username),這么方法是干嘛的呢,是根據(jù)你提供的用戶名它去查出用戶的具體信息,然后返回一個(gè)User對象(SpringSecurity中的User對象),這個(gè)User對象會(huì)攜帶著你需要驗(yàn)證的信息去驗(yàn)證,如果通過的話就進(jìn)行放行,那么User對象都會(huì)有哪些參數(shù)呢?來看下源碼:你可以只傳這三個(gè)參數(shù),當(dāng)然你也可以傳剩下的那些,比如密碼是否被鎖定,賬戶是否被凍結(jié),是否傳這些看你業(yè)務(wù)需要的,當(dāng)然你可以自定義一個(gè)類,然后讓它去實(shí)現(xiàn)UserDetails,實(shí)現(xiàn)里面的這些方法,因?yàn)檫@7個(gè)方法都是UserDetails接口里的。

在我的項(xiàng)目里沒有重寫,直接攜帶著用戶信息返回了User對象,需要的三個(gè)參數(shù)中第一個(gè)參數(shù)username已經(jīng)有了,是SpringSecurity為我們獲取的,至于怎么獲取的,我們在最后的文章中說原理的時(shí)候再談,然后就是password,有了username的話拿到password就很簡單,我們自定義了一個(gè)TeacherRepository類,里面有一個(gè)根據(jù)name獲取信息的方法,然后直接獲取密碼就好,最關(guān)鍵的是第三個(gè)參數(shù),這個(gè)參數(shù)的意思是讓我們傳入授權(quán),在我們這里就是角色,首先第一步我們先根據(jù)教師id獲取到角色信息,這個(gè)不難,關(guān)鍵是角色信息是一個(gè)List,因?yàn)橐粋€(gè)人可能有多個(gè)角色,意味著我們可以很簡單的拿到一個(gè)角色列表,然后我們需要用到一個(gè)類,這個(gè)類是GrantedAuthority它表示已經(jīng)被授權(quán)的權(quán)限,我們來構(gòu)建一個(gè)GrantedAuthority類型的數(shù)組,用來表示已經(jīng)被授權(quán)的角色,然后我們來實(shí)例化一個(gè)它的實(shí)現(xiàn)類SimpleGrantedAuthority這個(gè)類會(huì)接受一個(gè)String類型的role,然后去進(jìn)行授權(quán)。
什么意思呢?大概的流程是這樣的,首先我們從數(shù)據(jù)庫中讀取到了這個(gè)用戶對應(yīng)的角色,它是一個(gè)列表,記著我們要把這個(gè)列表中的值傳給SpringSecurity去判斷,看我這個(gè)列表里面有沒有你需要認(rèn)證的角色,如SpringSecurity需要一個(gè)admin角色才可以訪問/query。這時(shí)數(shù)據(jù)庫中這個(gè)用戶有一個(gè)角色為admin,那么就讓它訪問/query,GrantedAuthority、SimpleGrantedAuthority它們可以簡單理解為是用來幫你把數(shù)據(jù)庫中的角色交給SpringSecurity來驗(yàn)證。
代碼如下:

然后在我們之前的配置類中的configure方法就要改一下,因?yàn)槲覀冎笆菑膬?nèi)存中讀取的,現(xiàn)在是從數(shù)據(jù)庫中讀取出來的

我們需要驗(yàn)證的信息都在TeacherDetailsService中,因此我們還需要實(shí)例化一個(gè)TeacherDetailsService

細(xì)心的朋友可能會(huì)看到auth中還有一個(gè)passwordEncoder,這個(gè)下篇里面說,如果在SpringSecurity中使用自定義數(shù)據(jù)庫的加密方式,需要注意的是我們這樣寫完之后會(huì)報(bào)錯(cuò),當(dāng)時(shí)我也很懵,后來查閱了好多資料才發(fā)現(xiàn)的,角色認(rèn)證的一個(gè)大坑??!
經(jīng)過上面的信息認(rèn)證之后SpringSecurity發(fā)現(xiàn)我們輸入的信息是對的,但是再次登錄后還是會(huì)報(bào)錯(cuò)403,告訴你沒有認(rèn)證成功,沒有對應(yīng)的權(quán)限,這是為什么?后來查閱了SpringSecurity的API發(fā)現(xiàn)有這么一段

就是說當(dāng)你從數(shù)據(jù)庫中查到角色之后,雖然SimpleGrantedAuthority接收的是一個(gè)字符串角色,但是最終你返回的User對象中Collection<? extends GrantedAuthority> authorities這里需要的格式是ROLE_A這種格式,所有你需要在傳給User對象之前,將角色名稱前加一個(gè)ROLE_,比如我下面的這樣:RoleName就是我定義的ROLE_字符串,這樣才能夠被SpringSecurity所認(rèn)證。
![]()
之前看有的文章說是因?yàn)閔asRole需要在前面加ROLE_才可以,所以在配置文件中試了一下ROLE_ADMIN不好使,而且查閱官方API發(fā)現(xiàn)hashRole和hashAnyRole都不需要前面寫ROLE_

原來之所以不用寫是以為在SimpleGrantedAuthority傳入之后的格式中有了ROLE_限定
到此這篇關(guān)于SpringBoot基于SpringSecurity表單登錄和權(quán)限驗(yàn)證的示例的文章就介紹到這了,更多相關(guān)SpringSecurity表單登錄驗(yàn)證內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringSecurity表單配置之登錄成功及頁面跳轉(zhuǎn)原理解析
- Spring?Security登錄表單配置示例詳解
- SpringSecurity?表單登錄的實(shí)現(xiàn)
- SpringSecurity 自定義表單登錄的實(shí)現(xiàn)
- SpringSecurity 默認(rèn)表單登錄頁展示流程源碼
- Spring Security 表單登錄功能的實(shí)現(xiàn)方法
- Spring Security在標(biāo)準(zhǔn)登錄表單中添加一個(gè)額外的字段
- 最新Spring?Security實(shí)戰(zhàn)教程之表單登錄定制到處理邏輯的深度改造(最新推薦)
相關(guān)文章
Java并發(fā)編程Semaphore計(jì)數(shù)信號(hào)量詳解
這篇文章主要介紹了Java并發(fā)編程Semaphore計(jì)數(shù)信號(hào)量詳解,具有一定參考價(jià)值,需要的朋友可以了解下。2017-10-10
Maven Plugins報(bào)錯(cuò)的解決方法
本文主要介紹了Maven Plugins報(bào)錯(cuò)的解決方法,文中通過圖文介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-02-02
mybatis-plus的selectById(或者selectOne)在根據(jù)主鍵ID查詢實(shí)體對象的時(shí)候偶爾會(huì)出現(xiàn)nul
這篇文章主要介紹了mybatis-plus的selectById(或者selectOne)在根據(jù)主鍵ID查詢實(shí)體對象的時(shí)候偶爾會(huì)出現(xiàn)null的問題記錄,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
SpringBoot項(xiàng)目如何把接口參數(shù)中的空白值替換為null值(推薦)
這篇文章主要介紹了SpringBoot項(xiàng)目如何把接口參數(shù)中的空白值替換為null值(推薦),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01
java中的char占幾個(gè)字節(jié)實(shí)例分析
這篇文章主要介紹了java中的char占幾個(gè)字節(jié)實(shí)例分析的相關(guān)資料,需要的朋友可以參考下2017-04-04

