SpringBoot集成SpringSecurity(一) 入門

需求

公司打算重構權限系統,主要因爲現有的系統存在這些問題:

  1. 查詢用戶步驟繁瑣:選系統(主要是這一點)——用戶名——查詢按鈕;

  2. 簡化權限只分配到角色:現在權限全部彙總到一起,不知道權限從何而來;

  3. 角色承擔職責過多,雜而亂;

  4. 登錄名不唯一,無賬號找回功能

總之就是一個很亂的權限系統,考慮到security的強大功能,靈活易拓展(各種自定義),耦合性低,所以打算用security去是實現。

其實,我是不建議大家直接去了解security,大家可以先考慮一下沒引入security之前,登錄認證授權流程是怎樣的,因爲畢竟security也是按照這些去封裝代碼的。

如果直接去了解security的話,多少會有點迷茫和含糊,因爲它比較複雜(功能特別強大,拓展性極好),在知道本質之後去了解,一切都會顯得很清晰~~~

爲了方便入門,下面我主要講解的是沒有被security封裝之前的登錄授權流程代碼~~

如果這些您已瞭解,那麼請直接看下篇的登錄流程源碼分析。


前提

在瞭解security之前,我們必須知道這幾個東西:

  1. 什麼是會話?

  2. 授權的數據模型?

  3. RBAC方式


什麼是會話?

用戶認證通過後,爲了避免用戶的每次操作都進行認證可將用戶的信息保證在會話中。會話就是系統爲了保持當前 用戶的登錄狀態所提供的機制。

常見的方式有兩種:

  1. 基於session方式;
  2. 基於token方式;

session方式,我們可能很熟悉了,它的交互流程就是,用戶認證成功後,在服務端生成用戶相關的數據保存在session(當前會話)中,發給客戶端的 sesssion_id 存放到 cookie 中,這樣用戶客戶端請求時帶上 session_id 就可以驗證服務器端是否存在 session 數 據,以此完成用戶的合法校驗,當用戶退出系統或session過期銷燬時,客戶端的session_id也就無效了。如圖:
在這裏插入圖片描述
基於token方式如下圖:

​ 它的交互流程是,用戶認證成功後,服務端生成一個token發給客戶端,客戶端可以放到 cookie 或 localStorage 等存儲中,每次請求時帶上 token,服務端收到token通過驗證後即可確認用戶身份
在這裏插入圖片描述

基於session的認證方式由Servlet規範定製,服務端要存儲session信息需要佔用內存資源,客戶端需要支持 cookie;基於token的方式則一般不需要服務端存儲token,並且不限制客戶端的存儲方式。如今移動互聯網時代 更多類型的客戶端需要接入系統,系統多是採用前後端分離的架構進行實現,所以基於token的方式更適合。

授權的數據模型

即表結構的對應關係
在這裏插入圖片描述

主體(用戶id、賬號、密碼、…)

角色(角色id、角色名稱、…)

主體(用戶)和角色關係(用戶id、角色id、…)

權限(權限id、權限標識、權限名稱、資源名稱、資源訪問地址、…)

角色與權限的關係(角色id,權限id…)

RBAC方式

如何實現授權,可以通過RBAC方式實現授權,RBAC有兩種方式:

  1. 基於角色的訪問控制(存在硬編碼問題)
  2. 基於資源的訪問控制(推薦)

具體如下:

基於角色的訪問控制

用戶必須 具有查詢工資權限纔可以查詢員工工資信息等,訪問控制流程如下:

在這裏插入圖片描述

根據上圖中的判斷邏輯,授權代碼可表示如下:

if(主體.hasRole("總經理角色id")){ 
	查詢工資 
}

如果上圖中查詢工資所需要的角色變化爲總經理和部門經理,此時就需要修改判斷邏輯爲“判斷用戶的角色是否是 總經理或部門經理”,修改代碼如下:

if(主體.hasRole("總經理角色id") ||  主體.hasRole("部門經理角色id")){
	查詢工資 
}

由此,我們可以看出,以上存在硬編碼問題!

基於資源的訪問控制

在這裏插入圖片描述

根據上圖中的判斷,授權代碼可以表示爲:

if(主體.hasPermission("查詢工資權限標識")){     
	查詢工資 
}

優點:系統設計時定義好查詢工資的權限標識,即使查詢工資所需要的角色變化爲總經理和部門經理也不需要修改 授權代碼,系統可擴展性強


入門

在瞭解security之前,我們先來了解一下沒有security的時候,登錄流程是怎麼走的。

爲了防止迷路,我先說一下步驟:

  1. 搭建項目環境(applicationcontext.xml,springmvc.xml,登錄頁面,初始化spring容器等);

  2. 配置所需要的bean以及業務;

  3. 認證邏輯;

  4. 會話管理

    • 基於session,通過HttpSession操作,主要用到的方法有setAttribute(),getAttribute(),invalidate();
    • 在認證成功的時候調用setAttribute()方法儲存,在訪問資源的時候調用getAttribute(),在登出的時候調用invalidate();
  5. 授權功能

    其實授權的本質就是一個攔截器,通過頁面當前訪問的資源與後臺查到的用戶權限做匹配,如果一致,則放行。

以上部分我們重點講解3,5其餘步驟略。

認證邏輯

認證的流程爲:

  1. 首先,當用戶請求過來的時候,我們是不是需要判斷一下它傳過來的值是否爲空,即用戶名或者密碼爲空;
  2. 其次我們需要拿着用戶名字去我們數據庫查詢是否有這個用戶,沒有的話,直接拋異常“沒有該用戶”;
  3. 如果通過用戶名查到用戶的話,那我們是不是需要用它來跟用戶輸入的值去做對比,如果一致則放行,不一致則拋異常(“賬號或密碼錯誤”);

以上三點用代碼來表示的話,如下:

public User authentication(AuthenticationRequest authenticationRequest){
        if(authenticationRequest == null || StringUtils.isEmpty(authenticationRequest.getUsername()) || StringUtils.isEmpty(authenticationRequest.getPassword())){
            throw new RuntimeException("用戶名或密碼爲空");
        }

        User user = userDao.getUserByUsername(authenticationRequest.getUsername());
        if(Objects.isNull(user)){
            throw new RuntimeException("該用戶不存在!");
        }
        if(!authenticationRequest.getPassword().equals(a.getPassword())){
            throw new RuntimeException("用戶名或密碼錯誤!");
        }
        return user;
    }

其實這段代碼被security封裝到了一個叫userDetailService的類中,但是其最本質的功能跟這個是一樣的;

授權功能

流程如下:

  1. 爲了模仿授權功能的實現,我們增加一個r1的資源(訪問此路徑的前提是在用戶已認證的情況下),想要訪問此資源必須要有p1的權限;
  2. 現在一名叫‘王五’的用戶想訪問它,所以我們就需要判斷一下王五是否含有p1權限;
  3. 如果含有p1權限,則放行;

代碼如下:

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //用戶身份信息
        Object object = request.getSession().getAttribute(UserDto.SESSION_USER_KEY);
        if(object == null){
            //沒有認證
            writeContent(response,"請登錄");
        }
        UserDto userDto = (UserDto) object;
        //請求的url
        String requestURI = request.getRequestURI();
        if( userDto.getAuthorities().contains("p1") && requestURI.contains("/r/r1")){
            return true;
        }
        writeContent(response,"沒有權限,拒絕訪問");

        return false;
    }

其實這塊代碼也被security封裝到了userDetailService中,但是security可能跟這個有點出入,security它引入了一個AccessDecisionVoter用於投票選舉機制,又採用3種模式判定,這個我們在後面詳細解釋…

總結

至此,我們security種的認證授權最本質的代碼就說到這了,當然security的功能要比這強大太多,下一結我們去看看security的底層源碼,看看它就是是怎麼進行登錄授權流程的。

下一篇鏈接:SpringBoot集成SpringSecurity(二) 登錄認證流程解析

參考文獻

推薦視頻:https://www.bilibili.com/video/av73730658?from=search&seid=10438598876647660573

因爲我就是用這個視頻去入手的,特別適合入門,講的很透徹,大家感興趣的可以看看

另:如有總結不對的地方,麻煩大家指出,希望我們共同給進步_

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章