统一对象消息编程详解——访问控制机制

   对于一个框架的访问控制机制(或安全机制),我认为要满足以下两项:

1、最大的灵活性

      业务流程与访问控制应该是平行的两条线,一方面我们可以灵活的在业务线任何点上拆装访问控制,不应该受业务流程的约束,同时,对于业务流程来说,访问机制也是透明的。可比喻为如果业务流程是高速公路上的汽车,访问机制就是无形的栏杆,对于司机正常行驶来说看不到栏杆,但是他一旦超速,那栏杆立刻的显现出来。

2、最小的颗粒度

      访问控制的控制颗粒度越细越好,就像一个办公大楼,仅仅大门有门卫不行的,各屋子、甚至各柜子也要有锁。对于对象编程,我认为访问机制的最小颗粒度要能细化在每个对象的方法上,也就是对任意对象的、任意方法我们能加上不同的安全门。

在上面要求的基础上,我们看消息编程框架的访问控制机制的实现。

在模块工厂的配置文件中:

<module name="webauth"  classfile=".servletutils.application.TLWAuth" configfile="auth_config.xml"/>

TLWAuth模块类为我们的访问机制控制类,我们给它的名称“webauth”。我们给它指定了配置文件auth_config.xml,现在看配置文件来了解功能。

<?xml version="1.0" encoding="UTF-8" ?>
<moduleConfig>
    <params>
        <defaultPolicy value="member" />
        <defaultDenyMsg value="loginDeny" />
    </params>
    <!-- 拒绝消息表-->
    <msgTable>
        <msgid  value="anonymousDeny" >
            <msg action="anonymousDeny" destination="authModule"/>
        </msgid>
        <msgid  value="loginDeny" >
            <msg action="loginDeny" destination="authModule" />
        </msgid>
        <msgid  value="refusedUserMsg" >
            <msg action="IfUserFreezen" destination="memberModule" />
        </msgid>
        <msgid  value="adminDenyMsg" >
            <msg action="noAuth" destination="managerControl" />
        </msgid>
    </msgTable>
    <!-- 安全策略定义 -->
    <policies>
        <policy name="anonymous"
                  ip="*"
                  denyMsg="anonymousDeny"
                 />
        <policy name="member"
                user="*"
                refusedUserMsg="refusedUserMsg"
                role="member"
                tokenExpire="check"
                ip="*"
                denyMsg="loginDeny"
        />
        <policy name="admin"
                user="*"
                role="admin"
                ip="*"
                denyMsg="adminDenyMsg"
        />
    </policies>
    <!-- 对于每个模块定义策略 -->
    <authModules>
        <module name="clientJsonToMsg"    defaultPolicy="anonymous"  />
        <module name="managerControl"    defaultPolicy="admin"  denyMsg="adminDenyMsg"  login="anonymous" loginInput="anonymous"  />
        <module name="adminMemberControl"    defaultPolicy="admin"   />
        <module name="homepage"    defaultPolicy="anonymous"  denyMsg=""  http="member"  getuser="member" />
        <module name="servletDbTest"    defaultPolicy="member"    />
        <module name="infomationControl"    defaultPolicy="member"  />
        <module name="memberControl"    defaultPolicy="member"  />
        <module name="servletDbTest"    defaultPolicy="anonymous"  />   
    </authModules>
    <!--根据消息ID 定义策略,如app发送的json数据传来msgid -->
    <authMsgids>
        <msgid name="postInfo"    policy="member"  denyMsg=""  />
        <msgid name="getPublicKey"    policy="anonymous"   />
        <msgid name="regist"    policy="anonymous"   />
        <msgid name="login"    policy="anonymous"   />
    </authMsgids>
    <!--认证tag -->
    <authTags>
        <tag name="test"    policy="admin"  denyMsg=""  />
    </authTags>
</moduleConfig>

  首先我们定义安全策略 policy,当前配置文件里面定义了三种安全策略 ,分别是 anonymous、member、admin,代表匿名用户、会员、管理员,当然策略可以根据自己的需求随意定制,策略名字也可以随意的起。每个策略里定义了访问审核要求,例如role定义了限制用户的角色,ip定义了所要求的ip,在member里有一项tokenExpire,这定义了需要token过期检查,意味着这member策略用于token用户。denyMsg为审核拒绝后的执行的消息ID,在消息表里msgTable定义了消息ID的内容。

 <authModules>项目里定义了不同的模块的审核机制,基本从从语义可以看出意义,如

 <module name="managerControl"    defaultPolicy="admin"  denyMsg="adminDenyMsg"  login="anonymous" loginInput="anonymous"  />

 对应managerControl模块, 它的默认策略是admin,但是login和loginInput方法的策略是anonymous 。因为用户登录的页面是允许匿名的。除了login和loginInput方法,该模块的其他方法策略都是admin,也就是说要求管理员角色。如果访问拒绝,则执行拒绝消息"adminDenyMsg",在msgTable表中:

        <msgid  value="adminDenyMsg" >
            <msg action="noAuth" destination="managerControl" />
        </msgid>

adminDenyMsg消息的目的是"managerControl"模块,方法是"noAuth"。如果模块策略中没有定义denyMsg,则执行策略中的denyMsg,如果策略中也没有定义,则执行params项定义的默认拒绝消息defaultDenyMsg。

如果访问模块没有在这里定义,但还加了访问控制检查,那么执行默认的访问策略,params中的 defaultPolicy定义,本配置为member。

由此看来,我们访问控制机制的颗粒度落实到模块的方法级别上,对于模块的不同方法可以定义不同的安全策略。

authMsgids项是针对web服务或json客户端,针对客户端传来的消息msgId而定义不同策略,在上面配置中,登录login与注册regist策略为匿名,但是发信息postInfo则要求会员member。

authTags项定义了安全标签策略。某些时候对于方法里面需求安全审计时可以发送安全标签,通过安全标签对应的策略来审核。虽然我们的访问机制实现了安全tag,但我不太赞成这样,因为这需要在业务流程里面加访问控制代码,违反了上面说的透明原则。如果需要在代码里面加安全审计,我认为将一个方法分为两个方法,通过方法层面的访问控制会更灵活。

访问策略配置完毕,下面如何将这些策略应用到模块上,就像我们说的,安全机制对于模块是透明的,也就是模块自己不知道。这非常简单,在每个模块的配置文件项目中beforeMsgTable中添加一项消息即可,如对informationModule模块的getReply方法需要审核控制,则配置:

<beforeMsgTable>
    <action  value="getReply" >
        <msg action="authInModule" destination="webauth"/>
    </action>
</beforeMsgTable>

那么 当模块执行getReplay方法之前启动访问审核。如果对该模块所有的方法都审核 ,则将action设置为“*”,如下:

<action value="*" >

<msg action="authInModule" destination="webauth"/>

</action>

虽然可以给任意模块加审核机制,但实际应用来说,特别对于MVC框架,我们一般无需给后端的业务逻辑模块加审核,审核一般放在与用户接口的控制端。对于我们的框架,urlmap模块将url解析为控制模块,因此访问控制加在这里从而对所有的控制模块审核。看urlmap配置项:

<beforeMsgTable>
    <action value="toServlet">
        <msg action="auToLogin" destination="webUser" useInputMsg="false" usePreReturnMsg="false"/>
        <msg action="authInUrlMap" destination="webauth" useInputMsg="false" usePreReturnMsg="false"/>
    </action>
</beforeMsgTable>

urlmap模块的toServlet方法将url解析后的msg转到响应的控制模块,因此在该方法前加入访问控制。

如果我们需要在代码里面启动安全tag审核,则发出审核消息即可,如:

private void wtest1(Object fromWho, TLMsg msg) {
    TLMsg returnMsg =putMsg("webauth" ,createMsg().setAction("authTag")
            .setParam("tag","test"));
    if(returnMsg!=null)  //审核没有通过
        return;
    outData odata =  creatOutDataMsg("test");
    odata.addData("message","test----------:");
    putOutData(odata);
}

通过给审核模块webauth发送消息authTag启动审核,审核tag标识为“test”,在上面配置中,该tag对应的策略是 admin,即管理员权限。审核通过后继续执行后续代码。前面说过我不赞同将安全机制放到业务代码里,例如上面代码,审核机制加入后将变得僵化,审核机制对业务流程失去了透明性,同时我们无法灵活的拆装这个审核点。上面的方法可以拆分成两个方法:

 private void wtest1(Object fromWho, TLMsg msg) {
        getMsg(this ,createMsg().setAction("realtest"));
    }
    private void realtest(Object fromWho, TLMsg msg){
        outData odata =  creatOutDataMsg("test");
        odata.addData("message","test----------:");
        putOutData(odata);
    }

对要审核的方法调用不能直接调用,也要采用消息机制,这样审核模块才能发挥作用。在模块配置中加入对realtest的审核机制:

<beforeMsgTable>
    <action  value="realtest" >
        <msg action="authInModule" destination="webauth"/>
    </action>
</beforeMsgTable>

最后修改审核模块配置项,加入realtest的审核策略:

<module name="homepage"    defaultPolicy="anonymous"  denyMsg="" realtest="admin" http="member"  getuser="member" />

那么将由审核模块自动启动审核机制。

由于我们的框架能在运行中动态配置,因此审核机制的部署、修改也能立刻发生作用,也体现了访问控制的及时性。

业务流程与安全访问机制分开并行,除了灵活性以外,我认为对项目开发来说也能提高效率。业务开发人员可专心负责业务流程的开发,安全审核责任人负责业务流程中的安全审核点。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值