亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

基于shiro的自定義注解的擴展

YuboonaZhang / 656人閱讀

摘要:的自身注解的用法。所以自定義注解的作用很廣。但是在這里,我僅僅基于的來實現(xiàn)適用于它的自定義注解。其他的自定義的注解的編寫思路和這個也是類似的。

基于shiro的自定義注解的擴展

根據(jù)我的上一篇文章,權(quán)限設(shè)計的雜談中,涉及到了有關(guān)于前后端分離中,頁面和api接口斷開表與表層面的關(guān)聯(lián),另辟蹊徑從其他角度找到方式進行關(guān)聯(lián)。這里我們主要采取了shiro的自定義注解的方案。本篇文章主要解決以下的問題。

如何通過邏輯進行頁面與api接口的關(guān)聯(lián)。

shiro的自身注解的用法。

如何編寫自定義注解。

如何通過邏輯進行頁面與api接口的關(guān)聯(lián)

在表與表的結(jié)構(gòu)關(guān)系中,頁面和接口表最終都是與權(quán)限表進行的關(guān)聯(lián)(詳情請查看我的上一篇文章《權(quán)限設(shè)計的雜談》)。

我們現(xiàn)在希望用另一種方案去替代他,實現(xiàn)一個低成本同時兼顧一定程度的權(quán)限控制。這里我們引入兩個概念。業(yè)務(wù)模塊操作類型。

業(yè)務(wù)模塊

概念:將系統(tǒng)中的業(yè)務(wù)模塊抽象成一種數(shù)據(jù),我們可以用字符串的形式去表示,例如:角色管理對應(yīng)是role-manage、用戶管理對應(yīng)是user-manage等等。我們將系統(tǒng)中所存在的業(yè)務(wù)模塊通過“最小特權(quán)原則”進行劃分,最終形成一批可分配的數(shù)據(jù)。

使用原則:api接口和頁面以及功能從本質(zhì)上來說,都和業(yè)務(wù)模塊有邏輯關(guān)系,于是,我們可以對api接口與頁面(以及功能點)進行邏輯匹配,來判斷頁面與接口的關(guān)系。

操作類型

概念:將系統(tǒng)中的所有的操作類型抽象成一種數(shù)據(jù),我們也可以用字符串的形式去表示,例如:新增對應(yīng)的是add、分配對應(yīng)的是allot等等。我們將系統(tǒng)中所有的操作類型根據(jù)業(yè)務(wù)模塊通過“數(shù)據(jù)許可證”進行劃分,最終形成一批可分配的數(shù)據(jù)。

使用原則:頁面是展示,功能點是動作,而接口是最終動作的資源提供,通過“業(yè)務(wù)模塊”確定了調(diào)取的資源,通過“操作類型”確定了資源的使用方式。通過兩者可以大致無誤的判斷頁面的功能點觸發(fā)的接口是否在鑒權(quán)之內(nèi)。

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

數(shù)據(jù)庫中的頁面表或的api接口表中的數(shù)據(jù)就是真實有效嗎?

頁面或接口的實際使用,是以功能存在為前提,還是以數(shù)據(jù)庫表中的數(shù)據(jù)存在為前提。

權(quán)限結(jié)構(gòu)中,“控制對象”的存儲只有數(shù)據(jù)庫這一種途徑嗎?

我們從結(jié)論出發(fā)來看這幾個問題,首先“控制對象”的存儲除了在數(shù)據(jù)庫中也可以代碼中,也可以在配置文件中,并不一定非得在數(shù)據(jù)庫;那么接著回答第二個問題,當(dāng)數(shù)據(jù)庫存在的接口信息,而服務(wù)端并沒有開發(fā)這個接口的時候,數(shù)據(jù)庫的信本身就有問題,亦或者,數(shù)據(jù)庫里新增的接口必定是服務(wù)端上已經(jīng)部署的接口才能生效;接著就是第一個問題,那么數(shù)據(jù)庫中關(guān)于“控制對象”的表中的數(shù)據(jù)并不一定是真實有效的。所以我們可以得出以下的解決方案

我們可以在接口上用注解的形式補充“業(yè)務(wù)模塊”和“操作類型”的數(shù)據(jù)信息,這兩類信息都可以存于常量類中,

在數(shù)據(jù)庫添加創(chuàng)建頁面表結(jié)構(gòu)和頁面功能表結(jié)構(gòu)的時候,添加“業(yè)務(wù)模塊”和“操作類型”字段。

可以將“業(yè)務(wù)模塊”和“操作類型”的信息存于數(shù)據(jù)庫的字典表中。

模塊的新增或操作的新增,必定帶來了接口的新增,那么就會帶來一次系統(tǒng)部署活動,這個運維成本是無法減少的,并不能通過表結(jié)構(gòu)來減少。

但是這種方案僅適用于非強控制接口型的項目,在強控制型的接口項目仍然要將頁面與接口進行綁定,雖然這會帶來巨大的運維成本。另外也可以通過接口路由規(guī)則進行劃分,例如:/api/page/xxxx/(僅對頁面使用),/api/mobile/xxxxx(僅對移動端使用)將僅供頁面使用的接口進行分類,這類接口僅做認證不做授權(quán),也可以達到目的。
shiro的自身注解的用法

通過一個理論上的思路認可之后,剩下的則是付諸技術(shù)上的實踐,我們這邊采用的是Apache Shiro的安全框架,在Spring Boot的環(huán)境下應(yīng)用。簡要說明以下幾個shiro的注解。

注解名 作用
@RequiresAuthentication 作用于的類、方法、實例上。調(diào)用時,當(dāng)前的subject是必須經(jīng)過了認證的。
@RequiresGuest 作用于的類、方法、實例上。調(diào)用時,subject可以是guest狀態(tài)。
@RequiresPermissions 作用于的類、方法、實例上。調(diào)用時,需要判斷suject中是否包含當(dāng)前接口中的Permission(權(quán)限信息)。
@RequiresRoles 作用于的類、方法、實例上。調(diào)用時,需要判斷subject中是否包含當(dāng)前接口中的Role(角色信息)。
@RequiresUser 作用于的類、方法、實例上。調(diào)用時,需要判斷subject中是否當(dāng)前應(yīng)用中的用戶。
    /**
     * 1.當(dāng)前接口需要經(jīng)過"認證"過程
     * @return
     */
    @RequestMapping(value = "/info",method = RequestMethod.GET)
    @RequiresAuthentication
    public String test(){
        return "恭喜你,拿到了參數(shù)信息";
    }
    
    /**
     * 2.1.當(dāng)前接口需要經(jīng)過權(quán)限校驗(需包含 角色的查詢 或 菜單的查詢)
     * @return
     */
    @RequestMapping(value = "/info",method = RequestMethod.GET)
    @RequiresPermissions(value={"role:search","menu":"search"},logical=Logical.OR)
    public String test(){
        return "恭喜你,拿到了參數(shù)信息";
    }
    
    /**
     * 2.2.當(dāng)前接口需要經(jīng)過權(quán)限校驗(需包含 角色的查詢 與 菜單的查詢)
     * @return
     */
    @RequestMapping(value = "/info",method = RequestMethod.GET)
    @RequiresPermissions(value={"role:search","menu":"search"},logical=Logical.OR)
    public String test(){
        return "恭喜你,拿到了參數(shù)信息";
    }
    
    /**
     * 3.1.當(dāng)前接口需要經(jīng)過角色校驗(需包含admin的角色)
     * @return
     */
    @RequestMapping(value = "/info",method = RequestMethod.GET)
    @RequiresRoles(value={"admin"})
    public String test(){
        return "恭喜你,拿到了參數(shù)信息";
    }
    
    /**
     * 3.2.當(dāng)前接口需要經(jīng)過角色與權(quán)限的校驗(需包含admin的角色,以及角色的查詢 或 菜單的查詢)
     * @return
     */
    @RequestMapping(value = "/info",method = RequestMethod.GET)
    @RequiresRoles(value={"admin"})
    @RequiresPermissions(value={"role:search","menu":"search"},logical=Logical.OR)
    public String test(){
        return "恭喜你,拿到了參數(shù)信息";
    }
    
    

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

現(xiàn)在我們來回顧一下整個運轉(zhuǎn)的流程。

如何編寫自定義注解

但是僅僅是擁有shiro中的這5個注解肯定是不夠使用的。在實際的使用過程中,根據(jù)需求,我們會在權(quán)限認證中加入我們自己特有的業(yè)務(wù)邏輯的,我們?yōu)榱吮憬輨t可以采用自定義注解的方式進行使用。這種方法不僅僅適用于Apache Shiro,很多其他的框架如:Hibernate Validator、SpringMVC、甚至我們可以寫一套校驗體系,在aop中去驗證權(quán)限,這都是沒問題的。所以自定義注解的作用很廣。但是在這里,我僅僅基于shiro的來實現(xiàn)適用于它的自定義注解。

定義注解類

/**
 * 用于認證的接口的注解,組合形式默認是“或”的關(guān)系
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Auth {
    /**
     * 業(yè)務(wù)模塊
     * @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.獲取當(dāng)前主題
            Subject subject = this.getSubject();
            //2.驗證是否包含當(dāng)前接口的權(quán)限有一個通過則通過
            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("沒有訪問此接口的權(quán)限");
            }

        }
    }
}

定義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 {
        // 驗證權(quán)限
        try {
            ((AuthHandler) this.getHandler()).assertAuthorized(getAnnotation(mi));
        } catch (AuthorizationException ae) {
            if (ae.getCause() == null) {
                ae.initCause(new AuthorizationException("當(dāng)前的方法沒有通過鑒權(quán): " + 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);
    }
}
總體的思路順序:定義注解類(定義業(yè)務(wù)可使用的變量)->定義注解處理類(通過注解中的變量做業(yè)務(wù)邏輯處理)->定義注解的攔截器->定義aop的切面類->最后定義shiro的自定義注解啟用類。其他的自定義的注解的編寫思路和這個也是類似的。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/76662.html

相關(guān)文章

  • Shiro入門這篇就夠了【Shiro基礎(chǔ)知識、回顧URL攔截】

    摘要:細粒度權(quán)限管理就是數(shù)據(jù)級別的權(quán)限管理。張三只能查看行政部的用戶信息,李四只能查看開發(fā)部門的用戶信息。比如通過的攔截器實現(xiàn)授權(quán)。 前言 本文主要講解的知識點有以下: 權(quán)限管理的基礎(chǔ)知識 模型 粗粒度和細粒度的概念 回顧URL攔截的實現(xiàn) Shiro的介紹與簡單入門 一、Shiro基礎(chǔ)知識 在學(xué)習(xí)Shiro這個框架之前,首先我們要先了解Shiro需要的基礎(chǔ)知識:權(quán)限管理 1.1什...

    chenjiang3 評論0 收藏0
  • 基于Shiro,JWT實現(xiàn)微信小程序登錄完整例子

    摘要:小程序官方流程圖如下,官方地址如果此圖理解不清楚的地方也可參看我的博客本文是對接微信小程序自定義登錄的一個完整例子實現(xiàn),技術(shù)棧為。調(diào)用微信接口獲取和根據(jù)和自定義登陸態(tài)返回自定義登陸態(tài)給小程序端。 小程序官方流程圖如下,官方地址 : https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login....

    cfanr 評論0 收藏0
  • Shiro統(tǒng)一認證授權(quán)

    摘要:的統(tǒng)一認證授權(quán)是下面的一個簡單,易用的權(quán)限框架,對于單體應(yīng)用來講,完全能夠極好的,快速的滿足權(quán)限的需求,所以一般在做項目的時候,都會成為開發(fā)者的首選。 Shiro的統(tǒng)一認證授權(quán) Shiro是Apache下面的一個簡單,易用的Java權(quán)限框架,對于單體應(yīng)用來講,Shiro完全能夠極好的,快速的滿足權(quán)限的需求,所以一般在做項目的時候,Shiro都會成為開發(fā)者的首選。 可是,如果你需要做第二...

    cocopeak 評論0 收藏0
  • 不用 Spring Security 可否?試試這個小而美安全框架

    摘要:寫在前面在一款應(yīng)用的整個生命周期,我們都會談及該應(yīng)用的數(shù)據(jù)安全問題。用戶的合法性與數(shù)據(jù)的可見性是數(shù)據(jù)安全中非常重要的一部分。 寫在前面 在一款應(yīng)用的整個生命周期,我們都會談及該應(yīng)用的數(shù)據(jù)安全問題。用戶的合法性與數(shù)據(jù)的可見性是數(shù)據(jù)安全中非常重要的一部分。但是,一方面,不同的應(yīng)用對于數(shù)據(jù)的合法性和可見性要求的維度與粒度都有所區(qū)別;另一方面,以當(dāng)前微服務(wù)、多服務(wù)的架構(gòu)方式,如何共享Sessi...

    toddmark 評論0 收藏0
  • 《 Kotlin + Spring Boot : 下一代 Java 服務(wù)端開發(fā) 》

    摘要:下一代服務(wù)端開發(fā)下一代服務(wù)端開發(fā)第部門快速開始第章快速開始環(huán)境準備,,快速上手實現(xiàn)一個第章企業(yè)級服務(wù)開發(fā)從到語言的缺點發(fā)展歷程的缺點為什么是產(chǎn)生的背景解決了哪些問題為什么是的發(fā)展歷程容器的配置地獄是什么從到下一代企業(yè)級服務(wù)開發(fā)在移動開發(fā)領(lǐng)域 《 Kotlin + Spring Boot : 下一代 Java 服務(wù)端開發(fā) 》 Kotlin + Spring Boot : 下一代 Java...

    springDevBird 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<