成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

基于shiro的自定義注解的擴(kuò)展

YuboonaZhang / 613人閱讀

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

基于shiro的自定義注解的擴(kuò)展

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

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

shiro的自身注解的用法。

如何編寫(xiě)自定義注解。

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

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

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

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

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

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

操作類(lèi)型

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

現(xiàn)在我們來(lái)回顧一下整個(gè)運(yùn)轉(zhuǎn)的流程。

如何編寫(xiě)自定義注解

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

定義注解類(lèi)

/**
 * 用于認(rèn)證的接口的注解,組合形式默認(rèn)是“或”的關(guān)系
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Auth {
    /**
     * 業(yè)務(wù)模塊
     * @return
     */
    String[] module();
    /**
     * 操作類(lèi)型
     */
    String[] action();

}

定義注解的處理類(lèi)

/**
 * Auth注解的操作類(lèi)
 */
public class AuthHandler extends AuthorizingAnnotationHandler {


    public AuthHandler() {
        //寫(xiě)入注解
        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.驗(yàn)證是否包含當(dāng)前接口的權(quán)限有一個(gè)通過(guò)則通過(guò)
            boolean hasAtLeastOnePermission = false;
            for(String m:module){
                for(String ac:action){
                    //使用hutool的字符串工具類(lèi)
                    String permission = StrFormatter.format("{}:{}",m,ac);
                    if(subject.isPermitted(permission)){
                        hasAtLeastOnePermission=true;
                        break;
                    }
                }
            }
            if(!hasAtLeastOnePermission){
                throw new AuthorizationException("沒(méi)有訪(fǎng)問(wèn)此接口的權(quán)限");
            }

        }
    }
}

定義shiro攔截處理類(lèi)

/**
 * 攔截器
 */
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 {
        // 驗(yàn)證權(quán)限
        try {
            ((AuthHandler) this.getHandler()).assertAuthorized(getAnnotation(mi));
        } catch (AuthorizationException ae) {
            if (ae.getCause() == null) {
                ae.initCause(new AuthorizationException("當(dāng)前的方法沒(méi)有通過(guò)鑒權(quán): " + mi.getMethod()));
            }
            throw ae;
        }
    }
}

定義shiro的aop切面類(lèi)

/**
 * shiro的aop切面
 */
public class AuthAopInterceptor extends AopAllianceAnnotationsAuthorizingMethodInterceptor {
    public AuthAopInterceptor() {
        super();
        // 添加自定義的注解攔截器
        this.methodInterceptors.add(new AuthMethodInterceptor(new SpringAnnotationResolver()));
    }
}

定義shiro的自定義注解啟動(dòng)類(lèi)

/**
 * 啟動(dòng)自定義注解
 */
public class ShiroAdvisor extends AuthorizationAttributeSourceAdvisor {

    public ShiroAdvisor() {
        // 這里可以添加多個(gè)
        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);
    }
}
總體的思路順序:定義注解類(lèi)(定義業(yè)務(wù)可使用的變量)->定義注解處理類(lèi)(通過(guò)注解中的變量做業(yè)務(wù)邏輯處理)->定義注解的攔截器->定義aop的切面類(lèi)->最后定義shiro的自定義注解啟用類(lèi)。其他的自定義的注解的編寫(xiě)思路和這個(gè)也是類(lèi)似的。

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/76662.html

相關(guān)文章

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

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

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

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

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

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

    cocopeak 評(píng)論0 收藏0
  • 不用 Spring Security 可否?試試這個(gè)小而美安全框架

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

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

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

    springDevBird 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<