搜尋
首頁Javajava教程基於shiro的自訂註解的擴展-圖文詳解

基於shiro的自訂註解的擴展

這裡我們主要採取了shiro的自訂註解的方案。本篇文章主要解決以下的問題。

  1. 如何透過邏輯進行頁面與api介面的關聯。

  2. shiro的自身註解的用法。

  3. 如何寫自訂註解。

如何透過邏輯進行頁面與api介面的關聯

在表格與表格的結構關係中,頁面和介面表最終都是與權限表進行的關聯(詳情請查看我的上一篇文章《權限設計的雜談》)。
基於shiro的自訂註解的擴展-圖文詳解我們現在希望用另一個方案去取代他,實現一個低成本同時兼顧一定程度的權限控制。這裡我們引入兩個概念。 業務模組作業類型

  • 業務模組

    • #概念:將系統中的業務模組抽象化成一種數據,我們可以用字串的形式去表示,例如:角色管理對應是role-manage、使用者管理對應是user-manage等等。我們將系統中所存在的業務模組透過「最小特權原則」來劃分,最終形成一批可分配的資料。

    • 使用原則:api介面與頁面以及功能本質上來說,都和業務模組有邏輯關係,於是,我們可以對api介面與頁面(以及功能點)進行邏輯匹配,來判斷頁面與介面的關係。

  • 操作類型

    • #概念:將系統中的所有的運算類型抽象化成一種數據,我們也可以用字串的形式去表示,例如:新增對應的是add、分配對應的是allot等等。我們將系統中所有的操作類型根據業務模組透過「資料許可證」進行劃分,最終形成一批可分配的資料。

    • 使用原則:頁面是展示,功能點是動作,而介面是最終動作的資源提供,透過「業務模組」確定了調取的資源,透過「操作類型」確定了資源的使用方式。透過兩者可以大致無誤的判斷頁面的功能點觸發的介面是否在鑑權之內。

現在提出了這兩個概念,他們最終的實際的使用方式是什麼,我們先從以下幾個角度去思考一下。

  1. 資料庫中的頁表或的api介面表中的資料就是真實有效嗎?

  2. 頁面或介面的實際使用,是以功能存在為前提,還是以資料庫表中的資料存在為前提。

  3. 權限結構中,「控制物件」的儲存只有資料庫這一途徑嗎?

我們從結論出發來看這幾個問題,首先「控制物件」的儲存除了在資料庫中也可以程式碼中,也可以在設定檔中,不一定非得在資料庫;那麼接著回答第二個問題,當資料庫存在的介面訊息,而服務端並沒有開發這個介面的時候,資料庫的信本身就有問題,亦或者,資料庫裡新增的介面必定是服務端上已經部署的介面才能生效;接著就是第一個問題,那麼資料庫中關於「控制物件」的表中的資料並不一定是真實有效的。所以我們可以得到以下的解決方案

  1. 我們可以在介面上用註解的形式補充「業務模組」和「操作類型」的資料訊息,這兩類資訊都可以存於常數類別中,

  2. 在資料庫中新增建立頁面表結構和頁面功能表結構的時候,新增「業務模組」和「操作類型」字段。

  3. 可以將「業務模組」和「操作類型」的資訊存於資料庫的字典表中。

  4. 模組的新增或操作的新增,必定帶來了介面的新增,那麼就會帶來一次系統部署活動,這個運維成本是無法減少的,並不能透過表結構來減少。

基於shiro的自訂註解的擴展-圖文詳解

但是這種方案僅適用於非強控制介面型的項目,在強控制型的介面項目仍然要將頁面與介面進行綁定,雖然這會帶來巨大的運維成本。另外也可以透過介面路由規則進行劃分,例如:/api/page/xxxx/(僅對頁面使用),/api/mobile/xxxxx(僅對行動端使用)將僅供頁面使用的介面進行分類,這類別介面只做認證不做授權,也可以達到目的。

shiro的自身註解的用法

透過一個理論上的思路認可之後,剩下的則是付諸技術上的實踐,我們這邊採用的是Apache Shiro的安全框架,在Spring Boot的環境下應用。簡要說明以下幾個shiro的註解。

註解名稱
#@RequiresAuthentication #作用於的類別、方法、實例上。呼叫時,目前的subject是必須經過了認證的。
@RequiresGuest 作用於的類別、方法、實例上。呼叫時,subject可以是guest狀態。
@RequiresPermissions 作用於的類別、方法、實例上。呼叫時,需要判斷suject中是否包含目前介面中的Permission(權限資訊)。
@RequiresRoles 在作用的類別、方法、實例上。呼叫時,需要判斷subject中是否包含目前介面中的Role(角色資訊)。
@RequiresUser 作用於的類別、方法、實例上。呼叫時,需要判斷subject中是否目前應用中的使用者。
    /**
     * 1.当前接口需要经过"认证"过程
     * @return
     */
    @RequestMapping(value = "/info",method = RequestMethod.GET)
    @RequiresAuthentication
    public String test(){
        return "恭喜你,拿到了参数信息";
    }
    
    /**
     * 2.1.当前接口需要经过权限校验(需包含 角色的查询 或 菜单的查询)
     * @return
     */
    @RequestMapping(value = "/info",method = RequestMethod.GET)
    @RequiresPermissions(value={"role:search","menu":"search"},logical=Logical.OR)
    public String test(){
        return "恭喜你,拿到了参数信息";
    }
    
    /**
     * 2.2.当前接口需要经过权限校验(需包含 角色的查询 与 菜单的查询)
     * @return
     */
    @RequestMapping(value = "/info",method = RequestMethod.GET)
    @RequiresPermissions(value={"role:search","menu":"search"},logical=Logical.OR)
    public String test(){
        return "恭喜你,拿到了参数信息";
    }
    
    /**
     * 3.1.当前接口需要经过角色校验(需包含admin的角色)
     * @return
     */
    @RequestMapping(value = "/info",method = RequestMethod.GET)
    @RequiresRoles(value={"admin"})
    public String test(){
        return "恭喜你,拿到了参数信息";
    }
    
    /**
     * 3.2.当前接口需要经过角色与权限的校验(需包含admin的角色,以及角色的查询 或 菜单的查询)
     * @return
     */
    @RequestMapping(value = "/info",method = RequestMethod.GET)
    @RequiresRoles(value={"admin"})
    @RequiresPermissions(value={"role:search","menu":"search"},logical=Logical.OR)
    public String test(){
        return "恭喜你,拿到了参数信息";
    }

在我們的實際使用過程中,實際上只需要使用@RequiresPermissions和@RequiresAuthentication就可以了這一個註解就可以了,在上一小節的結尾,我們採取了業務模組與操作的結合方案來解耦頁面和api介面的關係,和apache Shiro的這種方式正好一致。但是@RequiresRoles這個我們盡可能不採用,因為角色的組合形式太多,角色名沒有辦法在接口中具象唯一化(很難指定接口歸某個角色調用,但是一定能知道接口歸屬於某些業務模組的某些操作。)

現在我們來回顧整個運作的流程。

基於shiro的自訂註解的擴展-圖文詳解

如何寫自訂註解

但是僅僅是擁有shiro中的這5個註解肯定是不夠使用的。在實際的使用過程中,根據需求,我們會在權限認證中加入我們自己特有的業務邏輯的,我們為了便捷則可以採用自訂註解的方式進行使用。這個方法不只適用於Apache Shiro,許多其他的框架如:Hibernate Validator、SpringMVC、甚至我們可以寫一套校驗體系,在aop中去驗證權限,這都是沒問題的。所以自訂註解的作用很廣。但是在這裡,我僅僅基於shiro的來實現適用於它的自訂註解。

  • 定義註解類別

/**
 * 用于认证的接口的注解,组合形式默认是“或”的关系
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Auth {
    /**
     * 业务模块
     * @return
     */
    String[] module();
    /**
     * 操作类型
     */
    String[] action();

}
  • #定義註解的處理類別

/**
 * Auth注解的操作类
 */
public class AuthHandler extends AuthorizingAnnotationHandler {


    public AuthHandler() {
        //写入注解
        super(Auth.class);
    }

    @Override
    public void assertAuthorized(Annotation a) throws AuthorizationException {
        if (a instanceof Auth) {
            Auth annotation = (Auth) a;
            String[] module = annotation.module();
            String[] action = annotation.action();
            //1.获取当前主题
            Subject subject = this.getSubject();
            //2.验证是否包含当前接口的权限有一个通过则通过
            boolean hasAtLeastOnePermission = false;
            for(String m:module){
                for(String ac:action){
                    //使用hutool的字符串工具类
                    String permission = StrFormatter.format("{}:{}",m,ac);
                    if(subject.isPermitted(permission)){
                        hasAtLeastOnePermission=true;
                        break;
                    }
                }
            }
            if(!hasAtLeastOnePermission){
                throw new AuthorizationException("没有访问此接口的权限");
            }

        }
    }
}
  • 定義shiro攔截處理類別

/**
 * 拦截器
 */
public class AuthMethodInterceptor extends AuthorizingAnnotationMethodInterceptor {


    public AuthMethodInterceptor() {
        super(new AuthHandler());
    }

    public AuthMethodInterceptor(AnnotationResolver resolver) {
        super(new AuthHandler(), resolver);
    }

    @Override
    public void assertAuthorized(MethodInvocation mi) throws AuthorizationException {
        // 验证权限
        try {
            ((AuthHandler) this.getHandler()).assertAuthorized(getAnnotation(mi));
        } catch (AuthorizationException ae) {
            if (ae.getCause() == null) {
                ae.initCause(new AuthorizationException("当前的方法没有通过鉴权: " + mi.getMethod()));
            }
            throw ae;
        }
    }
}
  • #定義shiro的aop切面類別

/**
 * shiro的aop切面
 */
public class AuthAopInterceptor extends AopAllianceAnnotationsAuthorizingMethodInterceptor {
    public AuthAopInterceptor() {
        super();
        // 添加自定义的注解拦截器
        this.methodInterceptors.add(new AuthMethodInterceptor(new SpringAnnotationResolver()));
    }
}
  • 定義shiro的自訂註解啟動類別

/**
 * 启动自定义注解
 */
public class ShiroAdvisor extends AuthorizationAttributeSourceAdvisor {

    public ShiroAdvisor() {
        // 这里可以添加多个
        setAdvice(new AuthAopInterceptor());
    }

    @SuppressWarnings({"unchecked"})
    @Override
    public boolean matches(Method method, Class targetClass) {
        Method m = method;
        if (targetClass != null) {
            try {
                m = targetClass.getMethod(m.getName(), m.getParameterTypes());
                return this.isFrameAnnotation(m);
            } catch (NoSuchMethodException ignored) {

            }
        }
        return super.matches(method, targetClass);
    }

    private boolean isFrameAnnotation(Method method) {
        return null != AnnotationUtils.findAnnotation(method, Auth.class);
    }
}
總體的想法順序:定義註解類別(定義業務可使用的變數) ->定義註解處理類別(透過註解中的變數做業務邏輯處理)->定義註解的攔截器->定義aop的切面類別->最後定義shiro的自訂註解啟用類別。其他的自訂的註解的編寫思路和這個也是類似的。

相關推薦:

自訂註解映射thinkPHP21自訂標籤庫的導入方法詳解

Java中關於自訂註解的具體介紹

shiro授權實作詳解

以上是基於shiro的自訂註解的擴展-圖文詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
如何將Maven或Gradle用於高級Java項目管理,構建自動化和依賴性解決方案?如何將Maven或Gradle用於高級Java項目管理,構建自動化和依賴性解決方案?Mar 17, 2025 pm 05:46 PM

本文討論了使用Maven和Gradle進行Java項目管理,構建自動化和依賴性解決方案,以比較其方法和優化策略。

如何使用適當的版本控制和依賴項管理創建和使用自定義Java庫(JAR文件)?如何使用適當的版本控制和依賴項管理創建和使用自定義Java庫(JAR文件)?Mar 17, 2025 pm 05:45 PM

本文使用Maven和Gradle之類的工具討論了具有適當的版本控制和依賴關係管理的自定義Java庫(JAR文件)的創建和使用。

如何使用咖啡因或Guava Cache等庫在Java應用程序中實現多層緩存?如何使用咖啡因或Guava Cache等庫在Java應用程序中實現多層緩存?Mar 17, 2025 pm 05:44 PM

本文討論了使用咖啡因和Guava緩存在Java中實施多層緩存以提高應用程序性能。它涵蓋設置,集成和績效優勢,以及配置和驅逐政策管理最佳PRA

如何將JPA(Java持久性API)用於具有高級功能(例如緩存和懶惰加載)的對象相關映射?如何將JPA(Java持久性API)用於具有高級功能(例如緩存和懶惰加載)的對象相關映射?Mar 17, 2025 pm 05:43 PM

本文討論了使用JPA進行對象相關映射,並具有高級功能,例如緩存和懶惰加載。它涵蓋了設置,實體映射和優化性能的最佳實踐,同時突出潛在的陷阱。[159個字符]

Java的類負載機制如何起作用,包括不同的類載荷及其委託模型?Java的類負載機制如何起作用,包括不同的類載荷及其委託模型?Mar 17, 2025 pm 05:35 PM

Java的類上載涉及使用帶有引導,擴展程序和應用程序類負載器的分層系統加載,鏈接和初始化類。父代授權模型確保首先加載核心類別,從而影響自定義類LOA

如何將Java的RMI(遠程方法調用)用於分佈式計算?如何將Java的RMI(遠程方法調用)用於分佈式計算?Mar 11, 2025 pm 05:53 PM

本文解釋了用於構建分佈式應用程序的Java的遠程方法調用(RMI)。 它詳細介紹了接口定義,實現,註冊表設置和客戶端調用,以解決網絡問題和安全性等挑戰。

如何使用Java的插座API進行網絡通信?如何使用Java的插座API進行網絡通信?Mar 11, 2025 pm 05:53 PM

本文詳細介紹了用於網絡通信的Java的套接字API,涵蓋了客戶服務器設置,數據處理和關鍵考慮因素,例如資源管理,錯誤處理和安全性。 它還探索了性能優化技術,我

如何在Java中創建自定義網絡協議?如何在Java中創建自定義網絡協議?Mar 11, 2025 pm 05:52 PM

本文詳細介紹了創建自定義Java網絡協議。 它涵蓋協議定義(數據結構,框架,錯誤處理,版本控制),實現(使用插座),數據序列化和最佳實踐(效率,安全性,維護

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
3 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器