锁定老帖子 主题:请问这样的细粒度权限能否用acegi实现?
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2006-01-05
robbin 写道 我认为合理的控制方式是在Web Action来进行拦截(本质上等于基于URL的控制), 对URL的拦截也是acegi的强项。 如果robbin指的真的是对url的拦截,我可以讲讲acegi如何对url拦截,其实就是一个filter |
|
返回顶楼 | |
发表时间:2006-01-05
Feiing 写道 我认为大多数人对 Acegi 都有些偏见, 如果稍微花点时间了解, 相信会改变看法, 正如上面某位仁兄所述, Acegi 的复杂度在于对多种环境的支持, 大多数应用也只是用到其中某些功能, 要做的只不过是把 example 的配置文件拷过来稍做修改 其实说了半天, 俺的观点就是 : acegi 是一个高度可扩展, 可复用的 security framework Feiing你好,早就听说过您的大名,小弟正是那个“某位仁兄”,望有机会一起探讨。 |
|
返回顶楼 | |
发表时间:2006-01-05
差沙 写道 robbin 写道 我认为合理的控制方式是在Web Action来进行拦截(本质上等于基于URL的控制), 对URL的拦截也是acegi的强项。 如果robbin指的真的是对url的拦截,我可以讲讲acegi如何对url拦截,其实就是一个filter 好阿,期待你的示例。 |
|
返回顶楼 | |
发表时间:2006-01-05
就robbin的web层给一个具体的例子,争取写的完善点。
首先要配置一个filter,这个filter用一个代理bean写在了spring里面,其实根正常的filter没有任何区别。 <bean id="securityEnforcementFilter" class="org.acegisecurity.intercept.web.SecurityEnforcementFilter"> <property name="filterSecurityInterceptor"> <ref local="filterInvocationInterceptor" /> </property> <property name="authenticationEntryPoint"> <ref local="authenticationProcessingFilterEntryPoint" /> </property> </bean> "filterInvocationInterceptor" 是一个拦截器,说是拦截器,其实就是在filter里面执行一下他的拦截方法,这里可没有什么aop. authenticationEntryPoint 交验失败的时候转到的地方,为什么说是地方,因为通过配置可以转到其它的url甚至其它的协议下(http 转到 https等等) |
|
返回顶楼 | |
发表时间:2006-01-05
<bean id="authenticationProcessingFilterEntryPoint" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint"> <property name="loginFormUrl"> <value>/error.security</value> </property> <property name="forceHttps"> <value>false</value> </property> </bean> 这个就是失败的时候转到的地方,我们可以配置url和是否使用https <bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor"> <property name="authenticationManager"> <ref bean="authenticationManager" /> </property> <property name="accessDecisionManager"> <ref local="httpRequestAccessDecisionManager" /> </property> <property name="objectDefinitionSource"> <value> CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON PATTERN_TYPE_APACHE_ANT /index.jsp=ROLE_ANONYMOUS,ROLE_USER /j_acegi_switch_user=ROLE_SUPERVISOR /login.security=ROLE_ANONYMOUS,ROLE_USER /test.do=ROLE_CODER /**.do*=ROLE_USER </value> </property> </bean> 这个就是前面提到的拦截器。简单解释一下: authenticationManager 在acegi里面的主要作用就是管理维护用户的权限角色等信息,比方说想要用户的ROLE就要在这里面拿了。里面配置了多种全县的来源,可以从DAO里面来(就是数据库里面),可以是cookies里面的,也可以是匿名的权限,每种权限都以一种Provider的形式提供: <bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager"> <property name="providers"> <list> <ref local="daoAuthenticationProvider" /> <ref local="anonymousAuthenticationProvider" /> <ref local="rememberMeAuthenticationProvider" /> </list> </property> </bean> objectDefinitionSource在acegi里面就是配置权限信息,说明哪一个url需要什么权限才能访问,acegi默认用<value>来表示,其实这正是acegi的不足之处,还好能够补救。我来说明一下: 我们知道在spring里面<value>标签比较特殊,spring首先找到这个属性的类型,然后把value里面的内容以String的类型取出来(Spring做了一下包装,为TypedString)。然后根据这个属性的类型找他的Editer,然后用Editer来处理String为需要的类型。但是我们不希望用String来表达url,很明显url里面有=就不会玩了。我们可以把这个信息写到数据库里面,然后读取,这里面不说了以前有一位高手已经解释过了。 接下来就是httpRequestAccessDecisionManager了,AccessDecisionManager在acegi里面是决策者,就是根据你所拥有的权限和访问URL需要的权限来决定你到底能不能访问。 <bean id="httpRequestAccessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased"> <property name="allowIfAllAbstainDecisions"> <value>false</value> </property> <property name="decisionVoters"> <list> <ref bean="roleVoter" /> </list> </property> </bean> 决策者里面是投票者,这个上面已经解释过了,一个投票者校验一种权限。整个流程已经说完了。 |
|
返回顶楼 | |
发表时间:2006-01-05
流程说完了,接下对上面提到的问题解释一下:
引用 先使用URL拦截的方式去对付大多数的情况,然后少数URL搞不定的再加一个接口,让Action自己去判别。这样用两个拦截器对Action进行拦截,如果Action实现了hasPermission接口,那么就交给Action自己判断,如果Action没有该接口,就查找内部的URL和权限的对照表来判断。 这个情况比较复杂,因为是要对Action进行调用,所以要看使用的web框架来定夺。是用不同Web框架要是用不同的Web框架拦截器。所以恐怕acegi力不从心,挺多在filter里面配置一下是否要是用Action自身校验。但是想法很好,赞。 引用 你怎么把信息有效的传递给Web层和其他的Facade层进行用户友好性的提示处理? acegi校验失败的时候会抛出AuthenticationException异常,然后放在session里面, 在错误转向页面可以这样是用 <%= ((AuthenticationException); session.getAttribute(AbstractProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY););.getMessage(); %> <%= session.getAttribute(AuthenticationProcessingFilter.ACEGI_SECURITY_LAST_USERNAME_KEY); %> <%= session.getAttribute(SecurityEnforcementFilter.ACEGI_SECURITY_ACCESS_DENIED_EXCEPTION_KEY); %> 不过这么用实在太难看了,晕了。可以自己用tag来搞定 引用 很多系统需要根据权限不同,生成不同的UI组件(例如管理员的菜单和普通用户菜单就肯定不一样),这也需要在Web层的View进行控制。 acegi对View的处理就是使用tag,原来的acegi好像没有什么tag,简直是烂,现在有了tag,说一下是用的方法,但是说实话他的tag实在是不够强。 老版的web.xml <taglib> <taglib-uri>http://acegisecurity.sf.net/authz</taglib-uri> <taglib-location>/WEB-INF/authz.tld</taglib-location> </taglib> 在页面中使用 <authz:authorize ifAllGranted="ROLE_SUPERVISOR"> <td> <A HREF="del.htm?id=<c:out value="${contact.id}"/>">Del</A> </td> </authz:authorize> ifAllGranted是说所有的权限都有,用','分割权限 可以替换成ifAnyGranted: ifNotGranted: <authz:authentication operation="username"/> 这个是用来显示你的权限信息的。 <authz:acl domainObject="${contact}" hasPermission="16,1"> <td><A HREF="<c:url value="del.htm"><c:param name="contactId" value="${contact.id}"/></c:url>">Del</A></td> </authz:acl> 这个是ACL的,acegi里面新推出的ACL模型实在是一大亮点,找时间写一个专门介绍acegi的ACL模型的帖子。 |
|
返回顶楼 | |
发表时间:2006-01-05
谢谢你的例子,不过我还看不太懂,有很多问题不解,等有空学习一把Acegi再来讨教。
引用 这个情况比较复杂,因为是要对Action进行调用,所以要看使用的web框架来定夺。是用不同Web框架要是用不同的Web框架拦截器。所以恐怕acegi力不从心,挺多在filter里面配置一下是否要是用Action自身校验。但是想法很好,赞。
使用Webwork的话写Action拦截器和配置拦截器都超简单,不赘述了。 使用Struts/Spring的话,可以使用Spring的拦截器。不过这里面我有一个很大的疑问:就是Spring的拦截器怎么去拿到HttpSession里面的用户信息,从而拿到role进行权限判别?Webwork的拦截器通过ThreadLocal方式的ActionContext提供了不依赖Servlet容器的相关信息,但是Spring没有提供相关设施,兴许Spring有某个提供了ServletContext的回调接口(我不熟悉spring MVC所以只是猜测),只要拦截器实现该接口就可以得到ServletContext,从而拿到HttpSession。然而这样的方式也和Servlet API偶合了,无法脱离容器进行单元测试(必须用Mock),还是不如Webwork方便。 引申一步,对于现在AJAX方式的分布式调用,都是跳过Web层直接访问业务bean的,这时候都需要获得HttpSession,进行身份识别,我不知道大家是怎么做的。 引用 acegi校验失败的时候会抛出AuthenticationException异常,然后放在session里面,
在错误转向页面可以这样是用 这种方式有点太粗了,即使权限不通过,也可能有n种不同情况需要分别处理,你必须自己定义一个异常继承的体系结构去应对不同的情况。这个时候,Acegi是否支持方便的抛出我们自定义的各种异常?这种情况对于web层处理起来更方便,特别是webwork。 Acegi可能是太通用了,从上面讨论我总感觉如果自己去写权限管理很简单的事情,如果用Acegi,会麻烦好多,特别是那么多配置和常量定义,让我望而生畏,而且特定项目的需求肯定不可避免对Acegi进行定制和扩展。 Acegi似乎是Spring对应于J2EE的JAAS实现,Spring Acegi vs J2EE JAAS, 但是Acegi比JAAS更强大,更灵活,可移植性更好,更适合对付系统资源方面的权限控制,而不是业务逻辑方面的权限控制。 |
|
返回顶楼 | |
发表时间:2006-01-05
引用 使用Struts/Spring的话,可以使用Spring的拦截器。不过这里面我有一个很大的疑问:就是Spring的拦截器怎么去拿到 HttpSession里面的用户信息,从而拿到role进行权限判别?Webwork的拦截器通过ThreadLocal方式的 ActionContext提供了不依赖Servlet容器的相关信息,但是Spring没有提供相关设施,兴许Spring有某个提供了 ServletContext的回调接口(我不熟悉spring MVC所以只是猜测),只要拦截器实现该接口就可以得到ServletContext,从而拿到HttpSession。然而这样的方式也和 Servlet API偶合了,无法脱离容器进行单元测试(必须用Mock),还是不如Webwork方便。
引申一步,对于现在AJAX方式的分布式调用,都是跳过Web层直接访问业务bean的,这时候都需要获得HttpSession,进行身份识别,我不知道大家是怎么做的。 自问自答一把。可以自己写一个ServletFilter,把Webwork那些对应ActionContext相关的代码拷贝过来,在ServletFilter里面初始化和组装,随后就可以在Spring拦截器里面用Webwork那种方式使用request,session,context了。不过还是不知道大家是怎么处理的? |
|
返回顶楼 | |
发表时间:2006-01-05
引用 下载了你的开源框架,没找到你在哪里用AOP加入role的代码。权限确实适合用AOP去解决。
bba96-security是我另一个开源项目,可能也会加到bba96里面去。其实也很简单,只是用到bba96的query接口,然后自己定义一套security的接口给具体项目的role, user, group, resource, permission,只有一个securityManager跟permissionInterceptor是实现类,可以很方便的实现数据权限,以及权限的允许,限制,包含,还可以通过多种方式(自身冗余字段/连接表字段/子查询)让user对resource在group关系上的权限继承,所需要做的只是让resource实现不同的接口,对resource在department/type等其他关系的,就只能同过数据权限,就不能继承了(当然实现起来也可以,但是复杂度更高),这样用AOP控制下来,你就发现在权限控制方面是很自由的了。只用维护一个permission表,就可以随意对resource进行细到每个字段,甚至是他的关联字段的控制。 acegi是很好,通用性也拌住了自己的脚,ACL也不是多么好的模型,用起来不会有让你有自由的感觉,不值得花太多功夫下去。不知道acegi有没有query接口,可以让用户实现,而它对于这个query接口来进行AOP的权限控制,我觉得这才是根本之道。 |
|
返回顶楼 | |
发表时间:2006-01-05
lllyq 写道 引用 下载了你的开源框架,没找到你在哪里用AOP加入role的代码。权限确实适合用AOP去解决。
bba96-security是我另一个开源项目,可能也会加到bba96里面去。其实也很简单,只是用到bba96的query接口,然后自己定义一套security的接口给具体项目的role, user, group, resource, permission,只有一个securityManager跟permissionInterceptor是实现类,可以很方便的实现数据权限,以及权限的允许,限制,包含,还可以通过多种方式(自身冗余字段/连接表字段/子查询)让user对resource在group关系上的权限继承,所需要做的只是让resource实现不同的接口,对resource在department/type等其他关系的,就只能同过数据权限,就不能继承了(当然实现起来也可以,但是复杂度更高),这样用AOP控制下来,你就发现在权限控制方面是很自由的了。只用维护一个permission表,就可以随意对resource进行细到每个字段,甚至是他的关联字段的控制。 acegi是很好,通用性也拌住了自己的脚,ACL也不是多么好的模型,用起来不会有让你有自由的感觉,不值得花太多功夫下去。不知道acegi有没有query接口,可以让用户实现,而它对于这个query接口来进行AOP的权限控制,我觉得这才是根本之道。 那就等着看你完整的框架代码了。bba96简单浏览了一遍,感觉还是很不错的。 |
|
返回顶楼 | |