SpringBoot基于SpringSecurity表單登錄和權(quán)限驗(yàn)證的示例
一、簡(jiǎn)介
上篇介紹了一個(gè)自己做的管理系統(tǒng),最近空閑的時(shí)間自己在繼續(xù)做,把之前登錄時(shí)候自定義的攔截器過(guò)濾器換成了基于SpringSecurity來(lái)做,其中遇到了很多坑,總結(jié)下,大家有遇到類(lèi)似問(wèn)題的話(huà)就當(dāng)是為大家閉坑吧。
二、項(xiàng)目實(shí)現(xiàn)功能和成果展示
首先來(lái)看下登錄界面:這是我輸入的一個(gè)正確的信息,點(diǎn)擊登錄后SpringSecurity會(huì)根據(jù)你輸入的用戶(hù)名和密碼去驗(yàn)證是否正確,如果正確的話(huà)就去你定義的頁(yè)面,我這里定義的是查詢(xún)教師信息頁(yè)面。來(lái)看下代碼吧。
三、準(zhǔn)備工作(前臺(tái)頁(yè)面、實(shí)體類(lèi))
實(shí)體類(lèi)Teacher:字段主要有id、name、sex、email、schedule_Id、password、phone,上面都加了Hibernate的驗(yàn)證,其他字段大家可以自己寫(xiě),然后生成getter和setter方法
再來(lái)看下前臺(tái)頁(yè)面,前臺(tái)我使用的是一個(gè)BootStrap的頁(yè)面,模板語(yǔ)言使用的是Thymeleaf,當(dāng)然為了能夠在頁(yè)面支持security的語(yǔ)法需要在上面加入一個(gè)security的引入標(biāo)簽
index.html"頁(yè)面
index.html中登錄信息:需要注意的是我的表單是提交到/teacher/login這個(gè)路由上,然后就是字段中的name屬性必須要和你Teacher實(shí)體類(lèi)中的字段名一致,不然頁(yè)面數(shù)據(jù)傳不到后臺(tái)。這里只截圖2個(gè)字段吧太長(zhǎng)了其他的字段都一樣該好名字就行
然后我們?cè)賮?lái)看下TeacherController中的代碼:
這里面的代碼是我之前沒(méi)使用SpringSecurity的時(shí)候?qū)懙?,現(xiàn)在注釋掉了,當(dāng)我們登錄成功之后就會(huì)到/query這個(gè)路由下的方法去執(zhí)行,也就是執(zhí)行查詢(xún)教師信息,先不看query方法,我們現(xiàn)在先來(lái)對(duì)接SpringSecurity,讓它先幫我們來(lái)進(jìn)行index中用戶(hù)名和密碼的登錄驗(yàn)證,然后再看query方法
四、使用SpringSecurity進(jìn)行表單驗(yàn)證登錄
要想使用SpringSecurity就需要現(xiàn)在pom.xml中加入SpringSecurity的依賴(lài),你可以指定版本號(hào)也可以不指定,我這里沒(méi)有指定
注意:當(dāng)你引入SpringSecurity之后當(dāng)你再次去啟動(dòng)項(xiàng)目的時(shí)候,SpringSecurity自動(dòng)會(huì)給你跳到一個(gè)對(duì)話(huà)框,讓你輸入賬號(hào)和密碼,這里的用戶(hù)名是user,密碼在你啟動(dòng)的時(shí)候它會(huì)有一個(gè)加密的密文,你只需要復(fù)制進(jìn)去就可以登錄。
接下來(lái)我們要想實(shí)現(xiàn)自定義的表單驗(yàn)證登錄和其他高級(jí)功能就需要使用配置類(lèi)來(lái)配置,在SpringBoot中新建一個(gè)配置類(lèi),讓它來(lái)繼承WebSecurityConfigurerAdapter,然后重寫(xiě)里面的configure方法,在里面定義我們的邏輯,來(lái)看下代碼吧:
上面的是我項(xiàng)目中的配置,有些是本文用不到的,分別解釋下:從開(kāi)始來(lái)說(shuō),http.formLogin的作用是使用form表單進(jìn)行登錄,也就是我們的index頁(yè)面。當(dāng)然你也可以使用Batic登錄,就是之前說(shuō)的默認(rèn)給你的登錄信息界面。
上面的URL是我們的index頁(yè)面的數(shù)據(jù)也就是登錄的字段數(shù)據(jù),當(dāng)時(shí)我們提交的路徑是/teacher/login,而我們這里的配置意味著讓SpringSecurity去處理我們index表單數(shù)據(jù),你這樣寫(xiě)SpringSecurity就知道對(duì)這個(gè)路徑進(jìn)行登錄驗(yàn)證處理。
請(qǐng)注意下面的代碼因?yàn)橛锌樱?/strong>
可以看到我這邊配置了2個(gè)Mathchers,如果不配置的話(huà)會(huì)出現(xiàn)什么狀況呢?你可能會(huì)遇到下面的這種錯(cuò)誤
什么意思呢?我先來(lái)簡(jiǎn)化出來(lái)一個(gè)簡(jiǎn)單的配置,下面的這段配置的意思:處理登錄的Url為/teacher/login,對(duì)任何的請(qǐng)求都進(jìn)行驗(yàn)證,下面的csrf先忽略,那么上面的定向次數(shù)太多是怎么來(lái)的呢?當(dāng)你點(diǎn)擊登錄之后,SpringSecurity會(huì)去處理/teacher/login這個(gè)請(qǐng)求,然后它發(fā)現(xiàn)這個(gè)請(qǐng)求也是需要驗(yàn)證的,于是乎就進(jìn)入了死循環(huán),它一直在驗(yàn)證。。。
要想解決這個(gè)問(wèn)題,其實(shí)也很簡(jiǎn)單,就是給它弄一個(gè)匹配器,告訴SpringSecurity,我在訪(fǎng)問(wèn)這個(gè)路徑的時(shí)候你要放行不要攔截,比如說(shuō)你可以這么寫(xiě):.antMatchers("/teacher/login").permitAll(),有的朋友可能看了我上面的代碼,你并不是這么寫(xiě)的啊,你沒(méi)有對(duì)/teacher/login放行?。∵€記得我上面說(shuō)的嗎在們登錄成功之后也就是/teacher/login驗(yàn)證之后是要去執(zhí)行/query方法去查詢(xún)教師信息的,因此我的匹配器匹配的是/query,所以我這么寫(xiě).antMatchers("/query").hasAnyRole("admin","stu")的時(shí)候并沒(méi)有permitAll,是因?yàn)楹竺娴膆asRole,表示看你當(dāng)前登錄的用戶(hù)有沒(méi)有admin或者是stu這樣的角色,有的話(huà)我就放行沒(méi)有的話(huà)就不放行,有的朋友可能會(huì)說(shuō)那怎么角色該在哪里定義呢?下面我來(lái)看一下
五、角色匹配
這個(gè)時(shí)候我們需要重寫(xiě)Adapter的另外一個(gè)configure方法注意這個(gè)方法的參數(shù)類(lèi)型是AuthenticationManagerBuilder,它是一個(gè)認(rèn)證管理構(gòu)建器,可以幫我們構(gòu)建出你要對(duì)什么東西進(jìn)行認(rèn)證,比如角色、用戶(hù)、密碼,我們先來(lái)寫(xiě)一個(gè)內(nèi)存認(rèn)證,后臺(tái)會(huì)說(shuō)怎么連數(shù)據(jù)庫(kù)去認(rèn)證權(quán)限
上面這段代碼的意思是:我的認(rèn)證用戶(hù)為安安,密碼為:123123,安安的角色是admin,只有這些信息正確之后我才讓你認(rèn)證成功,去執(zhí)行下面的邏輯。我們來(lái)看下演示:
這就是代表登錄成功了,至于上面的角色顯示什么的我都會(huì)說(shuō)到,那么我們來(lái)?yè)Q一個(gè),剛才/query中的hasRole里面是admin和stu,我把a(bǔ)dmin去掉看下能登錄成功嗎?需要有一個(gè)stu的角色才能在登錄成功之后查看信息,而我們現(xiàn)在的用戶(hù)名和密碼都正確的情況下,角色不正確能夠成功嗎?
可以看到即使是使用了上面正確的用戶(hù)名和密碼登錄,但是提示沒(méi)有權(quán)限,這個(gè)頁(yè)面是我自定義的錯(cuò)誤頁(yè)面,你的可能會(huì)提示403沒(méi)有這些樣式。
六、從數(shù)據(jù)庫(kù)中讀取角色來(lái)驗(yàn)證
在真實(shí)的開(kāi)發(fā)中,我們肯定是不會(huì)將用戶(hù)信息這種東西放到內(nèi)存中去的,肯定時(shí)從數(shù)據(jù)庫(kù)中讀取的,我在數(shù)據(jù)庫(kù)中新建了一張表,教師角色表,我們就從這張表讀取角色信息然后交給SpringSecurity去判斷角色
實(shí)體類(lèi)這里就不截圖了,然后我們?cè)赥eacherRoleRepository中有這么一個(gè)方法,就是根據(jù)TeacherId去查詢(xún)教師的角色,為了方便我這里就不去新建什么Service了,直接就TeacherRoleRepository調(diào)用里面的findByTeacherId()方法
接下來(lái),我們編寫(xiě)一個(gè)TeacherDetailsService它實(shí)現(xiàn)一個(gè)UserDetailsService接口,UserDetailsService里面只有一個(gè)方法就是loadUserByUsername(String username),這么方法是干嘛的呢,是根據(jù)你提供的用戶(hù)名它去查出用戶(hù)的具體信息,然后返回一個(gè)User對(duì)象(SpringSecurity中的User對(duì)象),這個(gè)User對(duì)象會(huì)攜帶著你需要驗(yàn)證的信息去驗(yàn)證,如果通過(guò)的話(huà)就進(jìn)行放行,那么User對(duì)象都會(huì)有哪些參數(shù)呢?來(lái)看下源碼:你可以只傳這三個(gè)參數(shù),當(dāng)然你也可以傳剩下的那些,比如密碼是否被鎖定,賬戶(hù)是否被凍結(jié),是否傳這些看你業(yè)務(wù)需要的,當(dāng)然你可以自定義一個(gè)類(lèi),然后讓它去實(shí)現(xiàn)UserDetails,實(shí)現(xiàn)里面的這些方法,因?yàn)檫@7個(gè)方法都是UserDetails接口里的。
在我的項(xiàng)目里沒(méi)有重寫(xiě),直接攜帶著用戶(hù)信息返回了User對(duì)象,需要的三個(gè)參數(shù)中第一個(gè)參數(shù)username已經(jīng)有了,是SpringSecurity為我們獲取的,至于怎么獲取的,我們?cè)谧詈蟮奈恼轮姓f(shuō)原理的時(shí)候再談,然后就是password,有了username的話(huà)拿到password就很簡(jiǎn)單,我們自定義了一個(gè)TeacherRepository類(lèi),里面有一個(gè)根據(jù)name獲取信息的方法,然后直接獲取密碼就好,最關(guān)鍵的是第三個(gè)參數(shù),這個(gè)參數(shù)的意思是讓我們傳入授權(quán),在我們這里就是角色,首先第一步我們先根據(jù)教師id獲取到角色信息,這個(gè)不難,關(guān)鍵是角色信息是一個(gè)List,因?yàn)橐粋€(gè)人可能有多個(gè)角色,意味著我們可以很簡(jiǎn)單的拿到一個(gè)角色列表,然后我們需要用到一個(gè)類(lèi),這個(gè)類(lèi)是GrantedAuthority它表示已經(jīng)被授權(quán)的權(quán)限,我們來(lái)構(gòu)建一個(gè)GrantedAuthority類(lèi)型的數(shù)組,用來(lái)表示已經(jīng)被授權(quán)的角色,然后我們來(lái)實(shí)例化一個(gè)它的實(shí)現(xiàn)類(lèi)SimpleGrantedAuthority這個(gè)類(lèi)會(huì)接受一個(gè)String類(lèi)型的role,然后去進(jìn)行授權(quán)。
什么意思呢?大概的流程是這樣的,首先我們從數(shù)據(jù)庫(kù)中讀取到了這個(gè)用戶(hù)對(duì)應(yīng)的角色,它是一個(gè)列表,記著我們要把這個(gè)列表中的值傳給SpringSecurity去判斷,看我這個(gè)列表里面有沒(méi)有你需要認(rèn)證的角色,如SpringSecurity需要一個(gè)admin角色才可以訪(fǎng)問(wèn)/query。這時(shí)數(shù)據(jù)庫(kù)中這個(gè)用戶(hù)有一個(gè)角色為admin,那么就讓它訪(fǎng)問(wèn)/query,GrantedAuthority、SimpleGrantedAuthority它們可以簡(jiǎn)單理解為是用來(lái)幫你把數(shù)據(jù)庫(kù)中的角色交給SpringSecurity來(lái)驗(yàn)證。
代碼如下:
然后在我們之前的配置類(lèi)中的configure方法就要改一下,因?yàn)槲覀冎笆菑膬?nèi)存中讀取的,現(xiàn)在是從數(shù)據(jù)庫(kù)中讀取出來(lái)的
我們需要驗(yàn)證的信息都在TeacherDetailsService中,因此我們還需要實(shí)例化一個(gè)TeacherDetailsService
細(xì)心的朋友可能會(huì)看到auth中還有一個(gè)passwordEncoder,這個(gè)下篇里面說(shuō),如果在SpringSecurity中使用自定義數(shù)據(jù)庫(kù)的加密方式,需要注意的是我們這樣寫(xiě)完之后會(huì)報(bào)錯(cuò),當(dāng)時(shí)我也很懵,后來(lái)查閱了好多資料才發(fā)現(xiàn)的,角色認(rèn)證的一個(gè)大坑!!
經(jīng)過(guò)上面的信息認(rèn)證之后SpringSecurity發(fā)現(xiàn)我們輸入的信息是對(duì)的,但是再次登錄后還是會(huì)報(bào)錯(cuò)403,告訴你沒(méi)有認(rèn)證成功,沒(méi)有對(duì)應(yīng)的權(quán)限,這是為什么?后來(lái)查閱了SpringSecurity的API發(fā)現(xiàn)有這么一段
就是說(shuō)當(dāng)你從數(shù)據(jù)庫(kù)中查到角色之后,雖然SimpleGrantedAuthority接收的是一個(gè)字符串角色,但是最終你返回的User對(duì)象中Collection<? extends GrantedAuthority> authorities這里需要的格式是ROLE_A這種格式,所有你需要在傳給User對(duì)象之前,將角色名稱(chēng)前加一個(gè)ROLE_,比如我下面的這樣:RoleName就是我定義的ROLE_字符串,這樣才能夠被SpringSecurity所認(rèn)證。
之前看有的文章說(shuō)是因?yàn)閔asRole需要在前面加ROLE_才可以,所以在配置文件中試了一下ROLE_ADMIN不好使,而且查閱官方API發(fā)現(xiàn)hashRole和hashAnyRole都不需要前面寫(xiě)ROLE_
原來(lái)之所以不用寫(xiě)是以為在SimpleGrantedAuthority傳入之后的格式中有了ROLE_限定
到此這篇關(guān)于SpringBoot基于SpringSecurity表單登錄和權(quán)限驗(yàn)證的示例的文章就介紹到這了,更多相關(guān)SpringSecurity表單登錄驗(yàn)證內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringSecurity表單配置之登錄成功及頁(yè)面跳轉(zhuǎn)原理解析
- Spring?Security登錄表單配置示例詳解
- SpringSecurity?表單登錄的實(shí)現(xiàn)
- SpringSecurity 自定義表單登錄的實(shí)現(xiàn)
- SpringSecurity 默認(rèn)表單登錄頁(yè)展示流程源碼
- Spring Security 表單登錄功能的實(shí)現(xiàn)方法
- Spring Security在標(biāo)準(zhǔn)登錄表單中添加一個(gè)額外的字段
- 最新Spring?Security實(shí)戰(zhàn)教程之表單登錄定制到處理邏輯的深度改造(最新推薦)
相關(guān)文章
詳解SpringBoot中的index首頁(yè)的訪(fǎng)問(wèn)、自定義Favicon圖標(biāo)
這篇文章主要介紹了SpringBoot中的index首頁(yè)的訪(fǎng)問(wèn)、自定義Favicon圖標(biāo),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-08-08Spring Boot Excel文件導(dǎo)出下載實(shí)現(xiàn)代碼
這篇文章帶領(lǐng)我們直接實(shí)現(xiàn)Excel文件的直接導(dǎo)出下載,后續(xù)開(kāi)發(fā)不需要開(kāi)發(fā)很多代碼,直接繼承已經(jīng)寫(xiě)好的代碼,增加一個(gè)Xml配置就可以直接導(dǎo)出。具體實(shí)現(xiàn)代碼大家跟隨小編一起通過(guò)本文學(xué)習(xí)吧2018-11-11JavaFX實(shí)現(xiàn)UI美觀(guān)效果代碼實(shí)例
這篇文章主要介紹了JavaFX實(shí)現(xiàn)UI美觀(guān)效果代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07使用@value注解取不到application.xml配置文件中的值問(wèn)題
這篇文章主要介紹了使用@value注解取不到application.xml配置文件中的值問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03SpringCloud Alibaba項(xiàng)目實(shí)戰(zhàn)之nacos-server服務(wù)搭建過(guò)程
Nacos 是阿里巴巴推出來(lái)的一個(gè)新開(kāi)源項(xiàng)目,這是一個(gè)更易于構(gòu)建云原生應(yīng)用的動(dòng)態(tài)服務(wù)發(fā)現(xiàn)、配置管理和服務(wù)管理平臺(tái)。本章節(jié)重點(diǎn)給大家介紹SpringCloud Alibaba項(xiàng)目實(shí)戰(zhàn)之nacos-server服務(wù)搭建過(guò)程,感興趣的朋友一起看看吧2021-06-06一文了解Java讀寫(xiě)鎖ReentrantReadWriteLock的使用
ReentrantReadWriteLock稱(chēng)為讀寫(xiě)鎖,它提供一個(gè)讀鎖,支持多個(gè)線(xiàn)程共享同一把鎖。這篇文章主要講解一下ReentrantReadWriteLock的使用和應(yīng)用場(chǎng)景,感興趣的可以了解一下2022-10-10Jenkins配置前端自動(dòng)打包部署全過(guò)程(若依項(xiàng)目)
Jenkins作為一個(gè)開(kāi)源的自動(dòng)化服務(wù)器,廣泛用于持續(xù)集成、持續(xù)部署(CI/CD)流程中,這篇文章主要給大家介紹了關(guān)于Jenkins配置前端自動(dòng)打包部署(若依項(xiàng)目)的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2024-09-09