首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

基於 Struts 框架的 RBAC 權限控制實作方案

     編輯:Java 相關知識

角色基礎存取控制 (RBAC) 是企業級資訊系統中最主流的權限模型。結合 Struts 的 MVC 架構,本文提出一種將權限驗證邏輯集中在基底 Action 類別、透過 struts-config.xml 參數映射 Action 與權限關係的實作方案,有效解決傳統做法分散、維護困難、資料庫查詢頻繁等問題。

RBAC 核心模型回顧

RBAC 引入「角色」作為中介層:

  • 使用者 ↔ 角色:多對多 (一個用戶可有多角色,一角色可屬多用戶)
  • 角色 ↔ 權限:多對多
  • 會話:用戶登入時激活的角色子集,權限為激活角色權限的聯集

授權流程:資源權限 → 角色 → 用戶,實現用戶與具體權限的邏輯解耦。

Struts 架構下的權限驗證切入點

Struts 應用中,功能模組對應 *.do 請求,由 ActionServlet 根據 struts-config.xml 分派至對應 Action。權限驗證的本質是:當前用戶是否擁有訪問該 Action (及其具體操作) 的權限?

既有方案痛點分析

方案優點缺點
各 Action 內硬編碼驗證簡單直觀邏輯分散、重複代碼多、修改困難、移植性差
URL-權限映射存資料庫靈活、好維護每次請求查庫、效能差;同一 Action 多操作 (增/刪/改) 需細粒度 URL 設計

本文方案:四大設計面向

1. 資料庫設計:標準化五表結構

不將 URL 存資料庫,僅存實體關係,驗證時由記憶體中用戶物件直接判斷:

-- 使用者表
OA_USER { id, sys_name, password, ... }

-- 角色表
OA_ROLE { id, role_name, ... }

-- 權限表 (對應功能點代碼,如 ProjectDelete)
OA_POWER { id, power_name, ... }

-- 使用者-角色 關聯表
OA_USER_ROLE { id, user_id, role_id }

-- 角色-權限 關聯表
OA_ROLE_POWER { id, role_id, power_id }

2. URL 請求設計:引入 actionType 參數

解決單一 Action 處理多操作 (CRUD) 的粒度問題:

// 傳統: /project.do (無法區分新增/刪除)
/project.do?actionType=ProjectAdd
/project.do?actionType=ProjectDelete
/project.do?actionType=ProjectUpdate

actionType 值直接對應 OA_POWER.power_name。

3. struts-config.xml 映射配置:Parameter 屬性存權限對應

利用 ActionMapping 的 parameter 屬性,以 actionType(Power_Name) 格式定義映射,多組用分號分隔:

<action path="/project"
        type="com.example.ProjectAction"
        name="projectForm"
        scope="request"
        parameter="ProjectAdd(ProjectAdd);ProjectDelete(ProjectDelete);ProjectUpdate(ProjectUpdate)"
        validate="false">
    <forward name="success" path="/projectList.do"/>
    <forward name="nopower" path="/noPower.jsp"/>
</action>

優點:映射隨 Action 定義集中管理,無需額外資料表,啟動時載入記憶體,零資料庫查詢開銷。

4. 權限驗證演算法:BaseAction 集中攔截

設計抽象基類 BaseAction,覆寫 execute() 統一驗證,子類實作 doExecute():

public abstract class BaseAction extends Action {

    public ActionForward execute(ActionMapping mapping, ActionForm form,
                                 HttpServletRequest request, HttpServletResponse response) {
        if (checkPower(request, mapping)) {
            return doExecute(mapping, form, request, response);
        } else {
            return mapping.findForward("nopower");
        }
    }

    // 子類必須實作具體業務邏輯
    public abstract ActionForward doExecute(ActionMapping mapping, ActionForm form,
                                            HttpServletRequest request, HttpServletResponse response);

    // 從 mapping.parameter 解析 actionType 對應的權限名稱
    private String getActionPower(ActionMapping mapping) {
        String actionType = request.getParameter("actionType");
        String param = mapping.getParameter(); // 格式: "Add(ADD);Del(DEL)"
        // 解析邏輯:找到 actionType 對應的 Power_Name
        // 例如 actionType=ProjectDelete -> 返回 "ProjectDelete"
        return parsePowerFromParameter(param, actionType);
    }

    // 核心驗證:登入用戶權限集合是否包含 needPower
    private boolean checkPower(HttpServletRequest request, ActionMapping mapping) {
        LoginUser loginUser = (LoginUser) request.getSession().getAttribute("currentUser");
        if (loginUser == null) return false; // 未登入
        
        String needPower = getActionPower(mapping);
        if (needPower == null) return true; // 無需權限控制的操作
        
        return loginUser.hasPower(needPower); // 用戶物件含權限集合,記憶體中 O(1) 判斷
    }
}

LoginUser 權限快取設計

用戶登入成功時,一次性查詢資料庫組裝權限集合存入 Session:

public class LoginUser {
    private String userId;
    private Set powers = new HashSet<>(); // 權限名稱集合
    
    public boolean hasPower(String powerName) {
        return powers.contains(powerName);
    }
    
    // 登入時由 Service 填充
    public void loadPowers(Connection conn) {
        // SQL: SELECT p.power_name FROM oa_power p
        // JOIN oa_role_power rp ON p.id = rp.power_id
        // JOIN oa_user_role ur ON rp.role_id = ur.role_id
        // WHERE ur.user_id = ?
        // 結果填入 this.powers
    }
}

方案優勢總結

  • 集中管理:驗證邏輯集中在 BaseAction,業務 Action 零侵入。
  • 高效能:權限集合登入時載入 Session,請求驗證純記憶體操作,零資料庫往返。
  • 細粒度:actionType 解決單 Action 多操作權限區分。
  • 易維護:映射關係在 struts-config.xml 直觀可見,修改即時生效 (重新載入配置或熱部署)。
  • 擴展性:LoginUser.hasPower() 可輕鬆擴展支援通配符、正則、SpEL 表達式等高級匹配。

遷移至 Spring MVC / 現代框架的啟示

雖然 Struts 1 已退役,但本方案的核心思想——「配置映射 + 基類攔截 + 會話快取權限」——在 Spring MVC 的 HandlerInterceptor、Shiro/Spring Security 的註解/配置式權限控制中均有體現。理解此經典實作,有助於深入掌握現代權限框架的底層原理。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved