论坛首页 Java企业应用论坛

用细粒度的Action做为你的系统权限

浏览 42112 次
该帖已经被评为精华帖
作者 正文
   发表时间:2005-01-21  
from http://eway.blogdriver.com
      权限系统是多数应用系统必不可以少的子系统。曾经为权限模型所困惑。今天突然想到用不同的Action代表不同的权限是实现权限控制是一个很好的做法。
    我们知道,所谓的权限控制,就是一个“权限主体对于权限客体做了什么操作”的问题。其中主体代表了权限系统的用户,组,或者角色;而客体代表了权限系统中需要被保护的资源。显然,客体(资源)+操作的组合就代表了权限。
    使用MVC框架或者模式的时候,我们往往会有一个类,代表用户的某一个操作。没有框架的时候,可以是一个Servlet,有框架的时候,比如struts,webwork,就是一个Action。我们往往会每个用户动作都会写一个Action。而这个Action往往是诸如:ListUserAction,RemoveUserAction,CreateMessageAction,ModifyUserStatusAction等等,这里的每一个Action都是一个用户的操作,而不经意之间,这些个Action类就代表了一个资源和权限的组合,也就成为了一个权限。同时,我们知道,在MVC框架中,请求一个Action类,要求把这个Action的mapping的名称传递值FrontController Servlet,以便于让Servlet知道请求的是哪一个Action,我们也可以方便的在ServletFilter或者Interceptor中获得所请求的Action别名。这一切都好办了,我们何不直接将Action别名作为用户的权限进行用户权限设置,在每次请求的时候,得到请求的Action别名到权限Map中比对?笔者eway已经在一个小项目中采用了这个办法,效果还好。不妨试试,说不定收到意象不到的好处。
   发表时间:2005-01-21  
我看Quake Wang是用这种方式来实现权限控制的,我现在也是基于这种方式来实现权限控制,但是具体实现方式又有所不同,做了一些改进。

本质上一个Action代表了一个请求的URL地址,而B/S项目本质上也就是只能根据URL来确定是否具备访问权限,从原理上来说,也是合适的。但是Action代表的URL可能未必和逻辑意义上的权限功能模块完全重合,既有可能大于,也有可能小于。

例如某个角色具备用户管理权限,而这个用户管理功能可能要对应六七个相关的Action,这就是逻辑意义上的权限大于Action,这种情况下在权限设置管理界面里面初始化某角色的权限,则是一件非常累人的事情,为了给一个角色增加一个功能权限,需要你分别设置六七个Action的权限。

再例如你控制一个简单的工作流,那么同一个Action ,会根据传递过去的不同的querystring来分派到不同的角色权限上,这就是同一个Action要针对不同的Role授予不同的权限了。

所以我觉得在Action上面再抽象出来一层Module,针对Module设置权限比较好。
0 请登录后投票
   发表时间:2005-01-21  
我以前也曾用类似的手段来实现权限控制,和robbin说的针对Module也有点类似,也有点差别。我的一个Action里面完成一组功能,这一组功能的权限需求是一样的。所有的Action继承自一个父类,这个父类负责根据实际请求的action class的名字去检查用户权限。
做小系统感觉不错,做大系统就显得麻烦,要为每一个action都要配置访问权限,虽然一个action完成一组功能,但是对于大系统,仍然有很多个action,太麻烦,感觉不够优雅。
当时这么设计是因为权限控制是在后来加上去的(至于为什么这样就不多说了),不想改动太多,只能从action的共同父类来着手,于是就想到在父类获取实际运行的子类的类名来做权限控制。本来打算是抽出权限Module的,但是这样要改的地方太多了。当然,这是题外话,如果一开始就这么设计的话就没这个问题了。
0 请登录后投票
   发表时间:2005-01-21  
我在webwork里是这样做的,首先定义一个接口:
public interface Protected {
    public boolean hasPermission();;
}


然后用拦截器做检查:
public class PermissionInterceptor implements Interceptor {
    public String intercept(ActionInvocation invocation); throws Exception {
        Action action = invocation.getAction();;
        if(action instanceof Protected); {
            if(!((Protected); action);.hasPermission(););{
                return NOPERMISSION;
            }
        }
        return invocation.invoke();;
    }
}


任何需要做权限检查的Action 实现这个接口即可,假设我们有一个管理员模块,我们可以写一个BaseAction:
public class BaseAdminAction implements Protected {
    private SecurityService securityService;

    public boolean hasPermission(); {
        return securityService.hasPermission(RemoteUser.get();, "admin");;
    }

    public void setSecurityService(SecurityService securityService); {
        this.securityService = securityService;
    }
}


在这里采用setter注入SecurityService,具体的校验逻辑都在SecurityService的实现里面,你可以用简单的查表法,也可以用很复杂的user-group-role-permission来实现。

在管理员模块下的所有Action可以extends它就可以了:
public class DeleteGroupAction extends BaseAdminAction {
    //......
}


如果你需要更细粒度的控制,或者是一些特殊逻辑权限检查,也可以选择重写这个方法
public class DeleteGroupAction implements Protected {
    public boolean hasPermission(); {
        return !group.getName();.equals("ADMIN_GROUP"); && securityService.hasPermission(RemoteUser.get();, "maintain_group");;
    }
}


这种做法就是Action组合好资源和操作,将其传递给SecurityService做检查

其实我们既可以选择直接在Action.hasPermission方法里面做一些动作,也可以选择注入不同的SecurityService实现,这样就很灵活了。
0 请登录后投票
   发表时间:2005-01-21  
robbin 写道
再例如你控制一个简单的工作流,那么同一个Action ,会根据传递过去的不同的querystring来分派到不同的角色权限上,这就是同一个Action要针对不同的Role授予不同的权限了。


我怎么觉得诸如queryString之类的权限控制不应在权限系统实现,基本上是个业务实现的问题。我觉得这个queryString往往是代表了“在什么情况下”这个权限有效的问题,如果都考虑进入权限系统的话,权限系统会非常庞大,难以维护。这种权限生效的“situation”的问题,我往往做到业务逻辑层中去check。

Action之上抽象一层Module的做法是不错。可是是不是可以考虑通过角色来解决诸如你这一类的问题呢?比如:用户管理的,我可以设置一个用户管理的角色,这一个角色可以授予执行createUser,removeUser,deleteUser权限,那么,我的用户是这个角色就可以咯。也就是说,是不是权限的粒度粗了,偶还是觉得用“资源+操作”去思考权限的粒度比较合适?比这个粒度粗的权限,就用角色来实现,比这个粒度细的权限就用业务实现。这样权限系统比较适中。
0 请登录后投票
   发表时间:2005-01-21  
Quake Wang 写道
我在webwork里是这样做的,首先定义一个接口:

那么一个action就不能同时在“需控制”和“不需控制”的域使用了吗?
0 请登录后投票
   发表时间:2005-01-21  
gigix 写道
那么一个action就不能同时在“需控制”和“不需控制”的域使用了吗?

我们可以在不需要控制的域里面,修改一下interceptor-stack,去掉PermissionInterceptor即可。
0 请登录后投票
   发表时间:2005-01-21  
Quake Wang 写道
gigix 写道
那么一个action就不能同时在“需控制”和“不需控制”的域使用了吗?

我们可以在不需要控制的域里面,修改一下interceptor-stack,去掉PermissionInterceptor即可。


您的实现是挺漂亮的。
可是授权是针对用户或者角色进行的呀,而这些Action是否需要保护是由系统管理员决定和授权给用户或者角色的,程序决定不好吧?
0 请登录后投票
   发表时间:2005-01-21  
的确,这是一个很好的入口,更好的入口是Service层.

对于权限,以我目前的理解,是要分成两个问题:权限引擎和权限引入.

引擎就是要能提供一个可以切入应用逻辑的运算模块,做到:
1.能将从业务逻辑中提取出权限逻辑.
2.能够根据权限逻辑,对于当前操作进行运算,得到权限判断结果.
引擎是个相对独立的部分.

引入就是要能做到尽量透明的在系统中插入权限控制,必须:
1.尽量对业务透明.
2.提供合适的控制粒度.
引入可以采用AOP的Interceptor,只要在合理的层次上插入,就可以完成权限控制了.

在Action层插入,是一个方式.但是,因为Action层次的信息仍然不够丰富.更好的方式是在Service层次插入(对DomainObject操作).

我着手做一个这样的东西已经有一段时间了,颇有进展,希望能在最近的项目中实际验证.

有兴趣可以关注: J.Blogs
0 请登录后投票
   发表时间:2005-01-21  
早先我做过一个系统,就是采用在Service层实现权限控制,但是后来发现不如在Action层实现起来方便。一方面是因为B/S应用中,客户端的请求动作本来就是一个一个的HTTP GET/POST,要做到最准确的权限控制,则必须针对Action。另一方面来说,如果你在Service层做权限控制,意味着你在Action还要写权限判定代码,那么就显得非常烦琐了。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics