SpringSecurity動(dòng)態(tài)加載用戶角色權(quán)限實(shí)現(xiàn)登錄及鑒權(quán)功能
很多人覺(jué)得Spring Security實(shí)現(xiàn)登錄驗(yàn)證很難,我最開(kāi)始學(xué)習(xí)的時(shí)候也這樣覺(jué)得。因?yàn)槲液镁枚紱](méi)看懂我該怎么樣將自己寫(xiě)的用于接收用戶名密碼的Controller與Spring Security結(jié)合使用,這是一個(gè)先入為主的誤區(qū)。后來(lái)我搞懂了:根本不用你自己去寫(xiě)Controller。
你只需要告訴Spring Security用戶信息、角色信息、權(quán)限信息、登錄頁(yè)是什么?登陸成功頁(yè)是什么?或者其他有關(guān)登錄的一切信息。具體的登錄驗(yàn)證邏輯它來(lái)幫你實(shí)現(xiàn)。
一、動(dòng)態(tài)數(shù)據(jù)登錄驗(yàn)證的基礎(chǔ)知識(shí)
在本號(hào)之前的文章中,已經(jīng)介紹了Spring Security的formLogin登錄認(rèn)證模式,RBAC的權(quán)限控制管理模型,并且針對(duì)Spring Security的登錄認(rèn)證邏輯源碼進(jìn)行了解析等等。我們所有的用戶、角色、權(quán)限信息都是在配置文件里面寫(xiě)死的,然而在實(shí)際的業(yè)務(wù)系統(tǒng)中,這些信息通常是存放在RBAC權(quán)限模型的數(shù)據(jù)庫(kù)表中的。下面我們來(lái)回顧一下其中的核心概念:
- RBAC的權(quán)限模型可以從用戶獲取為用戶分配的一個(gè)或多個(gè)角色,從用戶的角色又可以獲取該角色的多種權(quán)限。通過(guò)關(guān)聯(lián)查詢可以獲取某個(gè)用戶的角色信息和權(quán)限信息。
- 在源碼解析的文章中,我們知道如果我們不希望用戶、角色、權(quán)限信息寫(xiě)死在配置里面。我們應(yīng)該實(shí)現(xiàn)UserDetails與UserDetailsService接口,從而從數(shù)據(jù)庫(kù)或者其他的存儲(chǔ)上動(dòng)態(tài)的加載這些信息。
以上是對(duì)一些核心的基礎(chǔ)知識(shí)的總結(jié),如果您對(duì)這些知識(shí)還不是很清晰,建議您先往下讀本文。如果看完本文仍然理解困難,建議您翻看本號(hào)之前的文章。
二、UserDetails與UserDetailsService接口
- UserDetailsService接口有一個(gè)方法叫做loadUserByUsername,我們實(shí)現(xiàn)動(dòng)態(tài)加載用戶、角色、權(quán)限信息就是通過(guò)實(shí)現(xiàn)該方法。函數(shù)見(jiàn)名知義:通過(guò)用戶名加載用戶。該方法的返回值就是UserDetails。
- UserDetails就是用戶信息,即:用戶名、密碼、該用戶所具有的權(quán)限。
下面我們來(lái)看一下UserDetails接口都有哪些方法。
public interface UserDetails extends Serializable { //獲取用戶的權(quán)限集合 Collection<? extends GrantedAuthority> getAuthorities(); //獲取密碼 String getPassword(); //獲取用戶名 String getUsername(); //賬號(hào)是否沒(méi)過(guò)期 boolean isAccountNonExpired(); //賬號(hào)是否沒(méi)被鎖定 boolean isAccountNonLocked(); //密碼是否沒(méi)過(guò)期 boolean isCredentialsNonExpired(); //賬戶是否可用 boolean isEnabled(); }
現(xiàn)在,我們明白了,只要我們把這些信息提供給Spring Security,Spring Security就知道怎么做登錄驗(yàn)證了,根本不需要我們自己寫(xiě)Controller實(shí)現(xiàn)登錄驗(yàn)證邏輯。
三、實(shí)現(xiàn)UserDetails 接口
public class SysUser implements UserDetails{ String password(); //密碼 String username(); //用戶名 boolean accountNonExpired; //是否沒(méi)過(guò)期 boolean accountNonLocked; //是否沒(méi)被鎖定 boolean credentialsNonExpired; //是否沒(méi)過(guò)期 boolean enabled; //賬號(hào)是否可用 Collection<? extends GrantedAuthority> authorities; //用戶的權(quán)限集合 //省略構(gòu)造方法 //省略set方法 //省略get方法(即接口UserDetails的方法) }
我們就是寫(xiě)了一個(gè)適應(yīng)于UserDetails的java POJO類,所謂的 UserDetails接口實(shí)現(xiàn)就是一些get方法。get方法由Spring Security調(diào)用,我們通過(guò)set方法或構(gòu)造函數(shù)為 Spring Security提供UserDetails數(shù)據(jù)。
四、實(shí)現(xiàn)UserDetailsService接口
@Component public class MyUserDetailsService implements UserDetailsService{ @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { //這里從數(shù)據(jù)庫(kù)sys_user表里面查詢實(shí)體類對(duì)象。loadUser方法可使用Mybatis或JDBC或JPA自行實(shí)現(xiàn)。 SysUser sysUser = loadUser(username); // 判斷用戶是否存在 if(user == null) { throw new UsernameNotFoundException("用戶名不存在"); } //從數(shù)據(jù)庫(kù)該用戶所有的角色信息,所有的權(quán)限標(biāo)志 //遍歷所有的ROLE角色及所有的Authority權(quán)限(菜單、按鈕)。 //用逗號(hào)分隔他們的唯一標(biāo)志,具體過(guò)程自行實(shí)現(xiàn)。 sysUser.setAuthorities( AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_AMIN , system:user:delete")); //sysUser.setAccountNonLocked(true或false); return sysUser; } }
- 通常數(shù)據(jù)庫(kù)表sys_user字段要和SysUser屬性一一對(duì)應(yīng),比如username、password、enabled。但是比如accountNonLocked字段用于登錄多次錯(cuò)誤鎖定,但我們一般不會(huì)在表里存是否鎖定,而是存一個(gè)鎖定時(shí)間字段。通過(guò)鎖定時(shí)間是否大于當(dāng)前時(shí)間判斷賬號(hào)是否鎖定,所以實(shí)現(xiàn)過(guò)程中可以靈活做判斷并用好set方法,不必拘泥于一一對(duì)應(yīng)的形式。
- 角色是一種特殊的權(quán)限,在Spring Security我們可以使用hasRole(角色標(biāo)識(shí))表達(dá)式判斷用戶是否具有某個(gè)角色,決定他是否可以做某個(gè)操作;通過(guò)hasAuthority(權(quán)限標(biāo)識(shí))表達(dá)式判斷是否具有某個(gè)操作權(quán)限。
五、最后說(shuō)明
至此,我們將系統(tǒng)里面的所有的用戶、角色、權(quán)限信息都通過(guò)UserDetailsService和UserDetails告知了Spring Security。但是多數(shù)朋友可能仍然不知道該怎樣實(shí)現(xiàn)登錄的功能,其實(shí)剩下的事情很簡(jiǎn)單了:
- 寫(xiě)一個(gè)登錄界面,寫(xiě)一個(gè)登錄表單,表單使用post方法提交到默認(rèn)的/login路徑
- 表單的用戶名、密碼字段名稱默認(rèn)是username、password。
- 寫(xiě)一個(gè)登錄成功之后的跳轉(zhuǎn)頁(yè)面,比如index.html
然后把這些信息通過(guò)配置方式告知Spring Security ,以上的配置信息名稱都可以靈活修改。如果您不知道如何配置請(qǐng)參考本號(hào)之前的文章《formLogin登錄認(rèn)證模式》。
總結(jié)
以上所述是小編給大家介紹的SpringSecurity動(dòng)態(tài)加載用戶角色權(quán)限實(shí)現(xiàn)登錄及鑒權(quán)功能,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
如果你覺(jué)得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!
- SpringBoot+SpringSecurity處理Ajax登錄請(qǐng)求問(wèn)題(推薦)
- 解析SpringSecurity自定義登錄驗(yàn)證成功與失敗的結(jié)果處理問(wèn)題
- 解決SpringSecurity 一直登錄失敗的問(wèn)題
- SpringSecurity多表多端賬戶登錄的實(shí)現(xiàn)
- SpringBoot如何整合Springsecurity實(shí)現(xiàn)數(shù)據(jù)庫(kù)登錄及權(quán)限控制
- SpringSecurity6.x多種登錄方式配置小結(jié)
- SpringSecurity表單配置之登錄成功及頁(yè)面跳轉(zhuǎn)原理解析
- SpringSecurity集成第三方登錄過(guò)程詳解(最新推薦)
- Spring?Security重寫(xiě)AuthenticationManager實(shí)現(xiàn)賬號(hào)密碼登錄或者手機(jī)號(hào)碼登錄
相關(guān)文章
Java多線程之synchronized關(guān)鍵字的使用
這篇文章主要介紹了Java多線程之synchronized關(guān)鍵字的使用,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-04-04Spring Boot 項(xiàng)目發(fā)布到 Tomcat 服務(wù)器的操作步驟
這篇文章主要介紹了Spring Boot 項(xiàng)目發(fā)布到 Tomcat 服務(wù)器的操作步驟,需要的朋友可以參考下2017-04-04深入理解SpringMVC中央調(diào)度器DispatcherServlet
這篇文章主要介紹了SpringMVC核心之中央調(diào)度器DispatcherServlet的相關(guān)知識(shí),包括SpringMVC請(qǐng)求處理過(guò)程及SrpingMVC容器和spring?IOC容器關(guān)系,需要的朋友可以參考下2022-05-05jvm內(nèi)存溢出解決方法(jvm內(nèi)存溢出怎么解決)
jvm內(nèi)存溢出解決方法,詳細(xì)內(nèi)容看下面解釋2013-12-12詳解Spring Boot 定制HTTP消息轉(zhuǎn)換器
本篇文章主要介紹了詳解Spring Boot 定制HTTP消息轉(zhuǎn)換器,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-11-11SpringBoot統(tǒng)一返回JSON格式實(shí)現(xiàn)方法詳解
這篇文章主要介紹了SpringBoot統(tǒng)一返回JSON格式實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2023-02-02基于Spring Batch向Elasticsearch批量導(dǎo)入數(shù)據(jù)示例
本文介紹了基于Spring Batch向Elasticsearch批量導(dǎo)入數(shù)據(jù)示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-02-02Java實(shí)現(xiàn)生成Excel樹(shù)形表頭完整代碼示例
這篇文章主要介紹了Java實(shí)現(xiàn)生成Excel樹(shù)形表頭完整代碼示例,具有一定借鑒價(jià)值,需要的朋友可以參考下。2017-12-12