一、簡介
上篇介紹了一個自己做的管理系統,最近空閑的時間自己在繼續做,把之前登錄時候自定義的攔截器過濾器換成了基于SpringSecurity來做,其中遇到了很多坑,總結下,大家有遇到類似問題的話就當是為大家閉坑吧。
二、項目實現功能和成果展示
首先來看下登錄界面:這是我輸入的一個正確的信息,點擊登錄后SpringSecurity會根據你輸入的用戶名和密碼去驗證是否正確,如果正確的話就去你定義的頁面,我這里定義的是查詢教師信息頁面。來看下代碼吧。
三、準備工作(前臺頁面、實體類)
實體類Teacher:字段主要有id、name、sex、email、schedule_Id、password、phone,上面都加了Hibernate的驗證,其他字段大家可以自己寫,然后生成getter和setter方法
再來看下前臺頁面,前臺我使用的是一個BootStrap的頁面,模板語言使用的是Thymeleaf,當然為了能夠在頁面支持security的語法需要在上面加入一個security的引入標簽
index.html"頁面
index.html中登錄信息:需要注意的是我的表單是提交到/teacher/login這個路由上,然后就是字段中的name屬性必須要和你Teacher實體類中的字段名一致,不然頁面數據傳不到后臺。這里只截圖2個字段吧太長了其他的字段都一樣該好名字就行
然后我們再來看下TeacherController中的代碼:
這里面的代碼是我之前沒使用SpringSecurity的時候寫的,現在注釋掉了,當我們登錄成功之后就會到/query這個路由下的方法去執行,也就是執行查詢教師信息,先不看query方法,我們現在先來對接SpringSecurity,讓它先幫我們來進行index中用戶名和密碼的登錄驗證,然后再看query方法
四、使用SpringSecurity進行表單驗證登錄
要想使用SpringSecurity就需要現在pom.xml中加入SpringSecurity的依賴,你可以指定版本號也可以不指定,我這里沒有指定
注意:當你引入SpringSecurity之后當你再次去啟動項目的時候,SpringSecurity自動會給你跳到一個對話框,讓你輸入賬號和密碼,這里的用戶名是user,密碼在你啟動的時候它會有一個加密的密文,你只需要復制進去就可以登錄。
接下來我們要想實現自定義的表單驗證登錄和其他高級功能就需要使用配置類來配置,在SpringBoot中新建一個配置類,讓它來繼承WebSecurityConfigurerAdapter,然后重寫里面的configure方法,在里面定義我們的邏輯,來看下代碼吧:
上面的是我項目中的配置,有些是本文用不到的,分別解釋下:從開始來說,http.formLogin的作用是使用form表單進行登錄,也就是我們的index頁面。當然你也可以使用Batic登錄,就是之前說的默認給你的登錄信息界面。
上面的URL是我們的index頁面的數據也就是登錄的字段數據,當時我們提交的路徑是/teacher/login,而我們這里的配置意味著讓SpringSecurity去處理我們index表單數據,你這樣寫SpringSecurity就知道對這個路徑進行登錄驗證處理。
請注意下面的代碼因為有坑:
可以看到我這邊配置了2個Mathchers,如果不配置的話會出現什么狀況呢?你可能會遇到下面的這種錯誤
什么意思呢?我先來簡化出來一個簡單的配置,下面的這段配置的意思:處理登錄的Url為/teacher/login,對任何的請求都進行驗證,下面的csrf先忽略,那么上面的定向次數太多是怎么來的呢?當你點擊登錄之后,SpringSecurity會去處理/teacher/login這個請求,然后它發現這個請求也是需要驗證的,于是乎就進入了死循環,它一直在驗證。。。
要想解決這個問題,其實也很簡單,就是給它弄一個匹配器,告訴SpringSecurity,我在訪問這個路徑的時候你要放行不要攔截,比如說你可以這么寫:.antMatchers("/teacher/login").permitAll(),有的朋友可能看了我上面的代碼,你并不是這么寫的啊,你沒有對/teacher/login放行啊!還記得我上面說的嗎在們登錄成功之后也就是/teacher/login驗證之后是要去執行/query方法去查詢教師信息的,因此我的匹配器匹配的是/query,所以我這么寫.antMatchers("/query").hasAnyRole("admin","stu")的時候并沒有permitAll,是因為后面的hasRole,表示看你當前登錄的用戶有沒有admin或者是stu這樣的角色,有的話我就放行沒有的話就不放行,有的朋友可能會說那怎么角色該在哪里定義呢?下面我來看一下
五、角色匹配
這個時候我們需要重寫Adapter的另外一個configure方法注意這個方法的參數類型是AuthenticationManagerBuilder,它是一個認證管理構建器,可以幫我們構建出你要對什么東西進行認證,比如角色、用戶、密碼,我們先來寫一個內存認證,后臺會說怎么連數據庫去認證權限
上面這段代碼的意思是:我的認證用戶為安安,密碼為:123123,安安的角色是admin,只有這些信息正確之后我才讓你認證成功,去執行下面的邏輯。我們來看下演示:
這就是代表登錄成功了,至于上面的角色顯示什么的我都會說到,那么我們來換一個,剛才/query中的hasRole里面是admin和stu,我把admin去掉看下能登錄成功嗎?需要有一個stu的角色才能在登錄成功之后查看信息,而我們現在的用戶名和密碼都正確的情況下,角色不正確能夠成功嗎?
可以看到即使是使用了上面正確的用戶名和密碼登錄,但是提示沒有權限,這個頁面是我自定義的錯誤頁面,你的可能會提示403沒有這些樣式。
六、從數據庫中讀取角色來驗證
在真實的開發中,我們肯定是不會將用戶信息這種東西放到內存中去的,肯定時從數據庫中讀取的,我在數據庫中新建了一張表,教師角色表,我們就從這張表讀取角色信息然后交給SpringSecurity去判斷角色
實體類這里就不截圖了,然后我們在TeacherRoleRepository中有這么一個方法,就是根據TeacherId去查詢教師的角色,為了方便我這里就不去新建什么Service了,直接就TeacherRoleRepository調用里面的findByTeacherId()方法
接下來,我們編寫一個TeacherDetailsService它實現一個UserDetailsService接口,UserDetailsService里面只有一個方法就是loadUserByUsername(String username),這么方法是干嘛的呢,是根據你提供的用戶名它去查出用戶的具體信息,然后返回一個User對象(SpringSecurity中的User對象),這個User對象會攜帶著你需要驗證的信息去驗證,如果通過的話就進行放行,那么User對象都會有哪些參數呢?來看下源碼:你可以只傳這三個參數,當然你也可以傳剩下的那些,比如密碼是否被鎖定,賬戶是否被凍結,是否傳這些看你業務需要的,當然你可以自定義一個類,然后讓它去實現UserDetails,實現里面的這些方法,因為這7個方法都是UserDetails接口里的。
在我的項目里沒有重寫,直接攜帶著用戶信息返回了User對象,需要的三個參數中第一個參數username已經有了,是SpringSecurity為我們獲取的,至于怎么獲取的,我們在最后的文章中說原理的時候再談,然后就是password,有了username的話拿到password就很簡單,我們自定義了一個TeacherRepository類,里面有一個根據name獲取信息的方法,然后直接獲取密碼就好,最關鍵的是第三個參數,這個參數的意思是讓我們傳入授權,在我們這里就是角色,首先第一步我們先根據教師id獲取到角色信息,這個不難,關鍵是角色信息是一個List,因為一個人可能有多個角色,意味著我們可以很簡單的拿到一個角色列表,然后我們需要用到一個類,這個類是GrantedAuthority它表示已經被授權的權限,我們來構建一個GrantedAuthority類型的數組,用來表示已經被授權的角色,然后我們來實例化一個它的實現類SimpleGrantedAuthority這個類會接受一個String類型的role,然后去進行授權。
什么意思呢?大概的流程是這樣的,首先我們從數據庫中讀取到了這個用戶對應的角色,它是一個列表,記著我們要把這個列表中的值傳給SpringSecurity去判斷,看我這個列表里面有沒有你需要認證的角色,如SpringSecurity需要一個admin角色才可以訪問/query。這時數據庫中這個用戶有一個角色為admin,那么就讓它訪問/query,GrantedAuthority、SimpleGrantedAuthority它們可以簡單理解為是用來幫你把數據庫中的角色交給SpringSecurity來驗證。
代碼如下:
然后在我們之前的配置類中的configure方法就要改一下,因為我們之前是從內存中讀取的,現在是從數據庫中讀取出來的
我們需要驗證的信息都在TeacherDetailsService中,因此我們還需要實例化一個TeacherDetailsService
細心的朋友可能會看到auth中還有一個passwordEncoder,這個下篇里面說,如果在SpringSecurity中使用自定義數據庫的加密方式,需要注意的是我們這樣寫完之后會報錯,當時我也很懵,后來查閱了好多資料才發現的,角色認證的一個大坑!!
經過上面的信息認證之后SpringSecurity發現我們輸入的信息是對的,但是再次登錄后還是會報錯403,告訴你沒有認證成功,沒有對應的權限,這是為什么?后來查閱了SpringSecurity的API發現有這么一段
就是說當你從數據庫中查到角色之后,雖然SimpleGrantedAuthority接收的是一個字符串角色,但是最終你返回的User對象中Collection<? extends GrantedAuthority> authorities這里需要的格式是ROLE_A這種格式,所有你需要在傳給User對象之前,將角色名稱前加一個ROLE_,比如我下面的這樣:RoleName就是我定義的ROLE_字符串,這樣才能夠被SpringSecurity所認證。
之前看有的文章說是因為hasRole需要在前面加ROLE_才可以,所以在配置文件中試了一下ROLE_ADMIN不好使,而且查閱官方API發現hashRole和hashAnyRole都不需要前面寫ROLE_
原來之所以不用寫是以為在SimpleGrantedAuthority傳入之后的格式中有了ROLE_限定
到此這篇關于SpringBoot基于SpringSecurity表單登錄和權限驗證的示例的文章就介紹到這了,更多相關SpringSecurity表單登錄驗證內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!
原文鏈接:https://blog.csdn.net/qq_32967665/article/details/86296980