SpringSecurity動態加載用戶角色權限實現登陸及鑑權

file

不少人以爲Spring Security實現登陸驗證很難,我最開始學習的時候也這樣以爲。由於我很久都沒看懂我該怎麼樣將本身寫的用於接收用戶名密碼的Controller與Spring Security結合使用,這是一個先入爲主的誤區。後來我搞懂了:根本不用你本身去寫Controller。你只須要告訴Spring Security用戶信息、角色信息、權限信息、登陸頁是什麼?登錄成功頁是什麼?或者其餘有關登陸的一切信息。具體的登陸驗證邏輯它來幫你實現。html

1、動態數據登陸驗證的基礎知識

在本號以前的文章中,已經介紹了Spring Security的formLogin登陸認證模式,RBAC的權限控制管理模型,而且針對Spring Security的登陸認證邏輯源碼進行了解析等等。咱們全部的用戶、角色、權限信息都是在配置文件裏面寫死的,然而在實際的業務系統中,這些信息一般是存放在RBAC權限模型的數據庫表中的。下面咱們來回顧一下其中的核心概念:java

  • RBAC的權限模型能夠從用戶獲取爲用戶分配的一個或多個角色,從用戶的角色又能夠獲取該角色的多種權限。經過關聯查詢能夠獲取某個用戶的角色信息和權限信息。
  • 在源碼解析的文章中,咱們知道若是咱們不但願用戶、角色、權限信息寫死在配置裏面。咱們應該實現UserDetails與UserDetailsService接口,從而從數據庫或者其餘的存儲上動態的加載這些信息。

以上是對一些核心的基礎知識的總結,若是您對這些知識還不是很清晰,建議您先往下讀本文。若是看完本文仍然理解困難,建議您翻看本號以前的文章。spring

2、UserDetails與UserDetailsService接口

  • UserDetailsService接口有一個方法叫作loadUserByUsername,咱們實現動態加載用戶、角色、權限信息就是經過實現該方法。函數見名知義:經過用戶名加載用戶。該方法的返回值就是UserDetails。
  • UserDetails就是用戶信息,即:用戶名、密碼、該用戶所具備的權限。

下面咱們來看一下UserDetails接口都有哪些方法。數據庫

public interface UserDetails extends Serializable {
    //獲取用戶的權限集合
    Collection<!--? extends GrantedAuthority--> getAuthorities();

    //獲取密碼
    String getPassword();

    //獲取用戶名
    String getUsername();

    //帳號是否沒過時
    boolean isAccountNonExpired();

    //帳號是否沒被鎖定
    boolean isAccountNonLocked();

    //密碼是否沒過時
    boolean isCredentialsNonExpired();

    //帳戶是否可用
    boolean isEnabled();
}

如今,咱們明白了,只要咱們把這些信息提供給Spring Security,Spring Security就知道怎麼作登陸驗證了,根本不須要咱們本身寫Controller實現登陸驗證邏輯。springboot

3、實現UserDetails 接口

public class SysUser implements UserDetails{
    
    String password();  //密碼
    String username();  //用戶名
    boolean accountNonExpired;   //是否沒過時
    boolean accountNonLocked;   //是否沒被鎖定
    boolean credentialsNonExpired;  //是否沒過時
    boolean enabled;  //帳號是否可用
    Collection<!--? extends GrantedAuthority--> authorities;  //用戶的權限集合

    //省略構造方法
    //省略set方法
    //省略get方法(即接口UserDetails的方法)
}

咱們就是寫了一個適應於UserDetails的java POJO類,所謂的 UserDetails接口實現就是一些get方法。get方法由Spring Security調用,咱們經過set方法或構造函數爲 Spring Security提供UserDetails數據。ide

4、實現UserDetailsService接口

@Component
public class MyUserDetailsService implements UserDetailsService{

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            
       //這裏從數據庫sys_user表裏面查詢實體類對象。loadUser方法可以使用Mybatis或JDBC或JPA自行實現。
       SysUser sysUser =  loadUser(username);   

        // 判斷用戶是否存在 
       if(user == null)  {  throw  new  UsernameNotFoundException("用戶名不存在");  }

       //從數據庫該用戶全部的角色信息,全部的權限標誌
       //遍歷全部的ROLE角色及全部的Authority權限(菜單、按鈕)。
       //用逗號分隔他們的惟一標誌,具體過程自行實現。
       sysUser.setAuthorities(
               AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_AMIN , system:user:delete"));
        
        //sysUser.setAccountNonLocked(true或false);
        return sysUser;
    }
}
  • 一般數據庫表sys_user字段要和SysUser屬性一一對應,好比username、password、enabled。可是好比accountNonLocked字段用於登陸屢次錯誤鎖定,但咱們通常不會在表裏存是否鎖定,而是存一個鎖定時間字段。經過鎖定時間是否大於當前時間判斷帳號是否鎖定,因此實現過程當中能夠靈活作判斷並用好set方法,沒必要拘泥於一一對應的形式。
  • 角色是一種特殊的權限,在Spring Security咱們可使用hasRole(角色標識)表達式判斷用戶是否具備某個角色,決定他是否能夠作某個操做;經過hasAuthority(權限標識)表達式判斷是否具備某個操做權限。

5、最後說明

至此,咱們將系統裏面的全部的用戶、角色、權限信息都經過UserDetailsService和UserDetails告知了Spring Security。可是多數朋友可能仍然不知道該怎樣實現登陸的功能,其實剩下的事情很簡單了:函數

  • 寫一個登陸界面,寫一個登陸表單,表單使用post方法提交到默認的/login路徑
  • 表單的用戶名、密碼字段名稱默認是username、password。
  • 寫一個登陸成功以後的跳轉頁面,好比index.html

而後把這些信息經過配置方式告知Spring Security ,以上的配置信息名稱均可以靈活修改。若是您不知道如何配置請參考本號以前的文章《formLogin登陸認證模式》。post

期待您的關注

相關文章
相關標籤/搜索