﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-心情小站-随笔分类-权限相关</title><link>http://www.blogjava.net/RongHao/category/20773.html</link><description>心有多大，舞台就有多大</description><language>zh-cn</language><lastBuildDate>Wed, 06 Jun 2007 17:27:43 GMT</lastBuildDate><pubDate>Wed, 06 Jun 2007 17:27:43 GMT</pubDate><ttl>60</ttl><item><title>关于权限系统设计的一些问与答</title><link>http://www.blogjava.net/RongHao/archive/2007/06/05/122191.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Tue, 05 Jun 2007 09:36:00 GMT</pubDate><guid>http://www.blogjava.net/RongHao/archive/2007/06/05/122191.html</guid><wfw:comment>http://www.blogjava.net/RongHao/comments/122191.html</wfw:comment><comments>http://www.blogjava.net/RongHao/archive/2007/06/05/122191.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/RongHao/comments/commentRss/122191.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/RongHao/services/trackbacks/122191.html</trackback:ping><description><![CDATA[一个朋友留言，提了一些关心的问题，这里说说自己的想法（不一定对）。<span style="font-weight: bold;"><br>问题：</span>数据范围的控制：&#8220;事实上不是每个用户都可以看到所有记录的。以财务管理为例，部门经理只能查看金额小于1W的数据；而总经理则没有限制&#8221;。象这样要根据数据的某个字段对数据范围进行控制，应该实现呢，是通过AOP动态改变执行的SQL吗？这样似乎不太可行，如果要执行的SQL特别复杂，那动态改变SQL 就更难了。现在的应用中一般使用hibernate，这样的话就变成了动态改变HQL，也是难的。<br><span style="color: red;">回答：</span>目前在我的代码里就是通过AOP动态改变执行的SQL，改变HQL确实很困难，但是改变criteria就比较简单了。对于特别复杂的sql，我的建议是把这些SQL直接写到你的业务程序里去，或者单独配置出来，和ibatis比较类似。<br><br><span style="font-weight: bold;">问题：</span>单条数据ACL权限：由于数据是不断增加的，所以要对单条数据的ACL权限，不应该是数据已存在，然后再对存在的数据授权，应该是对某种规则进行授权。以你举的个人通讯录为例，各人自己维护自己的通讯记录，数据只对自己可见，要想实现对自己的数据的可再授权，应该是对符合某个规则的数据进行授权，也就是说 &#8220;要执行授权操作的人就是数据的拥有者&#8221;这是个规则，那是不是应该对这个规则授权呢。<br><span style="color: red;">回答：</span>我理解的和你不一样。我的理解是这样的，实际中我把单条数据的权限划分为拥有、浏览、修改、删除四种权限，用户拥有哪种权限就可以对数据进行相应哪种操作。&#8220;要执行授权操作的人就是数据的拥有者&#8221;也可以理解为&#8220;要执行授权操作的人就必须有该数据的拥有权限&#8221;，这可以理解为一种规则，但我更愿意把它理解为一种习惯，很显然对习惯授权是没有意义的。当然这里是存在规则的，这种规则简单的说是这样：当我新增一条数据时，哪些人对该条数据拥有拥有的权限，哪些人对该条数据拥有浏览的权限，哪些人对该条数据拥有修改的权限，哪些人对该条数据拥有删除的权限。权限相关记录会在新增这条数据时根据该规则生成。在上面的例子里，这一规则体现在：各人自己维护自己的通讯记录，数据只对自己可见。也就是说在用户新增自己的通讯记录时，系统同时往权限表里插入了该用户对该记录的一个拥有权限记录。<br><br><span style="font-weight: bold;">问题：</span>数据字段权限：要实现对某个字段的权限控制，那是不是应该所有字段应该有个默认的操作呢，或者默认就是只可以查看，要进行修改的话就必须授权。但是通常整个应用中的字段非常多，这样是乎不太合理。那是不是可以做成所有字段默认就是可以CRUD的，只有要控制的字段才进行权限判断。同样，由于使用 Hibernate来进行持久化，那对字段的控制是不是就变成了对类中属性的控制。<br><span style="color: red;">回答：</span>数据字段权限一直是一个很难办的事情，实际上我很倾向于把这个问题推到页面来解决。其实所有的权限控制最后都是要通过页面来表现的。其实对字段来说，所需要的权限也很简单：可见/不可见,只读/可修改。这样的话，通过标签的形式来控制字段的显示、只读就显得很自然。对字段的权限记录可以放入到数据库，或者xml中，与具体的pojo类没有关系，当渲染页面的时候，由标签来读取相关权限记录并控制显示。<br><br><span style="font-weight: bold;">问题：</span>角色权限的继承：角色权限的继承通过规则来做，这个规则应该怎么设计呢。<br><span style="color: red;">回答：</span>这个问题其实是一个分离关注点的问题。你可以抽象出一个规则接口，这个接口定义了对部门、角色下的用户而言，哪些权限是可以从部门角色继承的，继承几级，哪些是不可以的。然后再具体实现。更灵活的方式是定义出一个配置文件，运行时可以灵活修改。<br><br><br><img src ="http://www.blogjava.net/RongHao/aggbug/122191.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/RongHao/" target="_blank">ronghao</a> 2007-06-05 17:36 <a href="http://www.blogjava.net/RongHao/archive/2007/06/05/122191.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>对数据权限控制的实验</title><link>http://www.blogjava.net/RongHao/archive/2007/03/23/105948.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Fri, 23 Mar 2007 10:35:00 GMT</pubDate><guid>http://www.blogjava.net/RongHao/archive/2007/03/23/105948.html</guid><wfw:comment>http://www.blogjava.net/RongHao/comments/105948.html</wfw:comment><comments>http://www.blogjava.net/RongHao/archive/2007/03/23/105948.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/RongHao/comments/commentRss/105948.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/RongHao/services/trackbacks/105948.html</trackback:ping><description><![CDATA[一开始我把控制数据权限写在业务里，以订单管理为例，先讨论一个最简单的情况。管理员可以看所有的订单，而用户只能看自己的订单。这里的管理员是一个角色。我会这么写（一些次要代码都省略了）：<br /><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">   List getOrders(String userId){<br />             String sql;<br />             Role role</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">orgService.getRoleForUser(userId);<br />             </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">((</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">admin</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">).equals(role.getName()))<br />                   sql</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">select * from order</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;<br />             </span><span style="color: rgb(0, 0, 255);">else</span><span style="color: rgb(0, 0, 0);"><br />                   sql</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">select * from order where author=</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);">userId;<br />             Object o</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">excuteSql(sql);<br />             </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> excute(o);<br />        }</span></div><br />恩，不错，很好的完成了权限控制。过了没多久，公司发展了，老板增加了人手，老板发话了，我要设置区域管理员分管不同区域的订单。管理员分为北京地区管理员，上海地区管理员，其他地区管理员和总管理员。怎么办？修改代码吧<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">    List getOrders(String userId){<br />             String sql;<br />             Role role</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">orgService.getRoleForUser(userId);<br />             </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">((</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">admin</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">).equals(role.getName()))<br />                  sql</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">select * from order</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;<br />             </span><span style="color: rgb(0, 0, 255);">else</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">bjadmin</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">).equals(role.getName()))<br />                         sql</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">select * from order where area='beijing'</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;<br />             </span><span style="color: rgb(0, 0, 255);">else</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">shadmin</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">).equals(role.getName()))<br />                         sql</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">select * from order where area='shanghai'</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;<br />             </span><span style="color: rgb(0, 0, 255);">else</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">qtadmin</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">).equals(role.getName()))<br />                         sql</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">select * from order where area='qita'</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;<br />             </span><span style="color: rgb(0, 0, 255);">else</span><span style="color: rgb(0, 0, 0);"><br />                   sql</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">select * from order where author=</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);">userId;<br />             Object o</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">excuteSql(sql);<br />             </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> excute(o);<br />        }</span></div><br />恩恩，这就搞定了，可怎么也感觉不爽，也许该做点什么。一堆if/else权限判断让人心烦，再写个类把这些sql管理起来好了，那就动手吧<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">  </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> SqlManager{<br />          String getSql(String userId){<br />                  String sql;<br />          Role role</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">orgService.getRoleForUser(userId);<br />          </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">((</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">admin</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">).equals(role.getName()))<br />              sql</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">select * from order</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;<br />          </span><span style="color: rgb(0, 0, 255);">else</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">bjadmin</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">).equals(role.getName()))<br />                   sql</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">select * from order where area='beijing'</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;<br />          </span><span style="color: rgb(0, 0, 255);">else</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">shadmin</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">).equals(role.getName()))<br />                   sql</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">select * from order where area='shanghai'</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;<br />          </span><span style="color: rgb(0, 0, 255);">else</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">qtadmin</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">).equals(role.getName()))<br />                   sql</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">select * from order where area='qita'</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;<br />          </span><span style="color: rgb(0, 0, 255);">else</span><span style="color: rgb(0, 0, 0);"><br />            sql</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">select * from order where author=</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);">userId;<br />          </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> sql;<br />          }<br />  }</span></div><br />这样把权限判断移到SqlManager里，业务代码就清爽了很多,再增加管理员就修改SqlManager好了<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">    List getOrders(String userId){<br />             String sql</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">sqlManager.getSql(userId);<br />             Object o</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">excuteSql(sql);<br />             </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> excute(o);<br />        }</span></div><br />呵呵，看起来还不错。但是等等，我们的业务方法为什么需要userId这个参数呢，是啊是啊，权限判断用到了它，但是那和我业务又有什么关系呢，不爽。现在AOP不是很流行吗，你不用AOP怎么能说明你技术高呢？快用吧快用吧，用不着也要想着方法用。<br />业务方法简化为<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">    List getOrders(){<br />             String sql</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">""</span><span style="color: rgb(0, 0, 0);">;<br />             Object o</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">excuteSql(sql);<br />             </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> excute(o);<br />        }</span></div><br />对excuteSql方法我们来AOP一下，注入权限判断过的sql.嘿嘿，技术水平又一次得到了显现。业务方法是简单了，可我的SqlManager倒是复杂了，还是很不幸福。咋办？用个配置文件吧，hibernate不是老鼓励我们把sql写在配置文件里吗？<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">    &lt;xml&gt;<br />        &lt;sql role</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">admin</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">&gt;select * from order&lt;/sql&gt;<br />        &lt;sql role</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">bjadmin</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">&gt;select * from order where area</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">'beijing'&lt;/sql&gt;<br />        &lt;sql role</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">shadmin</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">&gt;select * from order where area</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">'shanghai'&lt;/sql&gt;<br />        &lt;sql role</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">qtadmin</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">&gt;select * from order where area</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">'qita'&lt;/sql&gt;<br />        &lt;sql role</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">none</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">&gt;select * from order where author</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">?&lt;/sql&gt;<br />    &lt;/xml&gt;</span></div><br />这样SqlManager就可以把行数缩小了，就可以敏捷一点了。<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> SqlManager{<br />          String getSql(String userId){<br />                  String sql;<br />          Role role</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">orgService.getRoleForUser(userId);<br />          sql</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">getSqlfromXml(role.getName());<br />          </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> sql;<br />          }<br />          <br />          String getSqlfromXml(String rolename){<br />                  <img src="http://www.blogjava.net/images/dot.gif" />.<br />          }<br />  }</span></div><br />以后再增加权限连类都不用修改了，改xml好了。等等，你是不是把问题太简单化了。现在不仅仅是订单，货物也要这么分区域管理。<br />不错，我们应该想着通用一下了。这样，把SqlManager抽象一下<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">        String </span><span style="color: rgb(0, 0, 255);">abstract</span><span style="color: rgb(0, 0, 0);"> getSqlfromXml(String rolename);</span></div><br />然后做几个子类好了 OrderSqlManager, GoodsSqlManager .<br />可是，哥们，书上说，要面向接口编程，你这样不太好吧。没事，再接口一下：<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">   </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">interface</span><span style="color: rgb(0, 0, 0);"> SqlManagerInterface{<br />           String getSql(String userId);<br />   }</span></div><br />还是没法用啊。也许现在可以看看acegi的provider机制了，把这一大堆SqlManager全部作为provider，根据不同的模块选择不同的provider，统一拦截excuteSql方法，生成不同的sql到数据库执行。xml不爽？db也可以。然后，再然后呢？改你的类名，重构，和acegi整合一下。<br />呵呵，完全是个人的一些想法，希望多批评提提意见。我想表达的意思是：也许把数据权限再抽象一些，以组件的形式来减少侵入是可以做到的。<img src ="http://www.blogjava.net/RongHao/aggbug/105948.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/RongHao/" target="_blank">ronghao</a> 2007-03-23 18:35 <a href="http://www.blogjava.net/RongHao/archive/2007/03/23/105948.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>对权限系统设计的再思考</title><link>http://www.blogjava.net/RongHao/archive/2007/03/21/105345.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Wed, 21 Mar 2007 11:04:00 GMT</pubDate><guid>http://www.blogjava.net/RongHao/archive/2007/03/21/105345.html</guid><wfw:comment>http://www.blogjava.net/RongHao/comments/105345.html</wfw:comment><comments>http://www.blogjava.net/RongHao/archive/2007/03/21/105345.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/RongHao/comments/commentRss/105345.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/RongHao/services/trackbacks/105345.html</trackback:ping><description><![CDATA[什么是权限系统，权限系统究竟在整个系统中起到什么作用，或者说权限系统必须提供哪些功能？<br />谈谈个人的看法，我认为授权和验证是一个权限系统最基本的功能，而一个更完善的权限系统会增加上如何验证和验证后如何处理这两种功能。<br />对于一个权限系统的基本元素，我觉得只有两个：Principal(权限主体)，权限。用户，用户组，角色等都可以抽象为权限主体这个概念；而权限则是资源+操作的抽象。权限可分为两种，一种纯粹就是资源，没有操作，也可以认为是默认操作；另外一种就是带操作的资源。授权本身没有什么说的，赋予权限主体权限；验证简单的说就是传入权限主体和当前操作需要的权限，然后验证返回说可以操作或是不可以操作yes/no。同时要注意的是验证的时候需要一个类（接口）来返回用户当前所拥有的权限，然后与当前操作需要的权限进行比对，最后返回比对结果。<br />以acegi为例，下面分开来说明：<br />首先，acegi是没有授权功能的，它简单把权限主体与资源配置在了xml里，当然这也带来了可扩展性，可以看一个配置：<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">                /index.jsp=ROLE_ANONYMOUS,ROLE_USER<br />                /hello.htm=ROLE_ANONYMOUS,ROLE_USER<br />                /logoff.jsp=ROLE_ANONYMOUS,ROLE_USER<br />                /switchuser.jsp=ROLE_SUPERVISOR<br />                /j_acegi_switch_user=ROLE_SUPERVISOR<br />                /acegilogin.jsp*=ROLE_ANONYMOUS,ROLE_USER<br />                /**=ROLE_USER</span></div><br />/index.jsp，/hello.htm这些URL都是资源，因为它默认的操作就是访问，所以访问特定URL就成了一个权限，ROLE_ANONYMOUS,ROLE_USER无疑就是权限主体。<br />Acegi对方法访问权限的配置也是和上面一样的。<br />然后，看看acegi的验证，其实它的验证就是一个个的Voter，当你访问一个方法时，由它获得当前用户和需要的权限（就是该方法），然后返回yes/no。<br />OK，这就是一个完整的权限系统了。当然acegi如果仅仅提供上面两个基本功能，它是不会向现在这样成功的，它最大的亮点就是提供了如何验证和验证后如何处理这两种功能。对url它提供了filter，方法也一样提供了Interceptor，这就是如何验证，和我们在action里验证没有任何区别，只是换了一种方式而已。然后它验证后的处理方式：yes就继续往下执行,no就抛出异常最后再处理这个异常。我们在执行每个action前同样也可以做到这一点。<br />这里着重要提到的是数据权限。比如说A只能对部门A下的数据有查看权限，B可以对部门A的数据有修改权限和对部门B的数据的查看权限。<br />看起来这个需求是比较麻烦的，但是我们可以按上面说的拆分以下：<br />资源1：部门A下的数据  ；资源2：部门B下的数据<br />操作1：查看；    操作2：修改<br />产生四种权限：<br />权限1：资源1+操作1 ；权限2：资源1+操作2；权限3：资源2+操作1；权限4：资源2+操作2<br />权限主体A拥有权限：1 ； 权限主体B拥有权限：2，3<br />这样就非常清晰了。<br />总结：我始终认为拥有授权和验证功能就完成了一个完整的权限系统。至于如何去校验权限，不管你是filter还是aop那是具体实现时的细节，采取的不同策略。而验证后的处理则是和不同策略相对应的。在你考虑设计一个权限系统时首先考虑的是如何实现授权和验证，而不是一开始就考虑我是采取filter，还是aop，还是动态改变sql。<br />谢谢wolfsquare，它的<a href="/wolfsquare/archive/2006/07/04/56606.html">blog相关</a><img src ="http://www.blogjava.net/RongHao/aggbug/105345.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/RongHao/" target="_blank">ronghao</a> 2007-03-21 19:04 <a href="http://www.blogjava.net/RongHao/archive/2007/03/21/105345.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Acegi ACL使用说明</title><link>http://www.blogjava.net/RongHao/archive/2007/03/20/105069.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Tue, 20 Mar 2007 11:07:00 GMT</pubDate><guid>http://www.blogjava.net/RongHao/archive/2007/03/20/105069.html</guid><wfw:comment>http://www.blogjava.net/RongHao/comments/105069.html</wfw:comment><comments>http://www.blogjava.net/RongHao/archive/2007/03/20/105069.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/RongHao/comments/commentRss/105069.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/RongHao/services/trackbacks/105069.html</trackback:ping><description><![CDATA[本文假设你对Acegi其他部分已经比较熟悉。Acegi 的ACL控制是建立在对相应业务方法拦截的基础上的。这里以Acegi自带的contacts例子来说明。<b><br />先看看总的配置</b>：<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">bean </span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="contactManagerSecurity"</span><span style="color: rgb(255, 0, 0);"> class</span><span style="color: rgb(0, 0, 255);">="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />      </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="authenticationManager"</span><span style="color: rgb(0, 0, 255);">&gt;&lt;</span><span style="color: rgb(128, 0, 0);">ref </span><span style="color: rgb(255, 0, 0);">bean</span><span style="color: rgb(0, 0, 255);">="authenticationManager"</span><span style="color: rgb(0, 0, 255);">/&gt;&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />      </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="accessDecisionManager"</span><span style="color: rgb(0, 0, 255);">&gt;&lt;</span><span style="color: rgb(128, 0, 0);">ref </span><span style="color: rgb(255, 0, 0);">local</span><span style="color: rgb(0, 0, 255);">="businessAccessDecisionManager"</span><span style="color: rgb(0, 0, 255);">/&gt;&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />      </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="afterInvocationManager"</span><span style="color: rgb(0, 0, 255);">&gt;&lt;</span><span style="color: rgb(128, 0, 0);">ref </span><span style="color: rgb(255, 0, 0);">local</span><span style="color: rgb(0, 0, 255);">="afterInvocationManager"</span><span style="color: rgb(0, 0, 255);">/&gt;&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />      </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="objectDefinitionSource"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />         </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">value</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />            sample.contact.ContactManager.getAll=AFTER_ACL_COLLECTION_READ<br />            sample.contact.ContactManager.getById=AFTER_ACL_READ<br />            sample.contact.ContactManager.delete=ACL_CONTACT_DELETE<br />            sample.contact.ContactManager.deletePermission=ACL_CONTACT_ADMIN<br />            sample.contact.ContactManager.addPermission=ACL_CONTACT_ADMIN<br />         </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">value</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />      </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />   </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">bean</span><span style="color: rgb(0, 0, 255);">&gt;</span></div>该拦截器实现了org.aopalliance.intercept.MethodInterceptor接口。在方法被调用之前，拦截器会先调用 AuthenticationManager判断用户身份是否已验证，然后从objectDefinitionSource中获取方法所对应的权限，再调用AccessDecisionManager来匹配用户权限和方法对应的权限。如果用户没有足够权限调用当前方法，则抛出 AccessDeniedException使方法不能被调用。方法调用后会调用AfterInvocationManager对返回的结果进行再次处理。下面依次说明。<br /><b>AccessDecisionManager的配置</b>：<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">bean </span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="businessAccessDecisionManager"</span><span style="color: rgb(255, 0, 0);"> class</span><span style="color: rgb(0, 0, 255);">="org.acegisecurity.vote.AffirmativeBased"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />      </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="allowIfAllAbstainDecisions"</span><span style="color: rgb(0, 0, 255);">&gt;&lt;</span><span style="color: rgb(128, 0, 0);">value</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">false</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">value</span><span style="color: rgb(0, 0, 255);">&gt;&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />      </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="decisionVoters"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />         </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">list</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />            </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">ref </span><span style="color: rgb(255, 0, 0);">local</span><span style="color: rgb(0, 0, 255);">="roleVoter"</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br />            </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">ref </span><span style="color: rgb(255, 0, 0);">local</span><span style="color: rgb(0, 0, 255);">="aclContactReadVoter"</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br />            </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">ref </span><span style="color: rgb(255, 0, 0);">local</span><span style="color: rgb(0, 0, 255);">="aclContactDeleteVoter"</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br />            </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">ref </span><span style="color: rgb(255, 0, 0);">local</span><span style="color: rgb(0, 0, 255);">="aclContactAdminVoter"</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br />         </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">list</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />      </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />   </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">bean</span><span style="color: rgb(0, 0, 255);">&gt;</span></div>AccessDecisionManager接口有decide()和support()方法。decide()方法决策是否批准通过即方法是否容许调用，如果没抛出AccessDeniedException则为允许访问资源，否则拒绝访问。support()方法是根据配置属性和受保护资源的类来判断是否需要对该资源作出决策判断。<br />AccessDecisionManager的 decisionVoters属性需要一个或多个Voter(投票者)，Voter必须实现AccessDecisionVoter 接口。Voter的工作是去匹配用户已拥有的权限和受保护的资源要求的权限，在该资源有相应权限的情况下，如果匹配则投允许票，否则投反对票。 <br />allowIfAllAbstainDecisions属性表示是否允许所有都弃权时就通过。Voter的实现类RoleVoter在当受保护资源的名字由ROLE_开始时才参与投票。<br />AccessDecisionManager有三个实现类，功能各不相同:<br />AffirmativeBased: 当至少有一个Voter投允许票时才通过<br />UnanimousBased: 没有Voter投反对票时才通过<br />ConsensusBased: 当所有Voter都投允许票时才通过<br /><b>下面列出一个Voter的配置</b>：<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">bean </span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="aclContactDeleteVoter"</span><span style="color: rgb(255, 0, 0);"> class</span><span style="color: rgb(0, 0, 255);">="org.acegisecurity.vote.BasicAclEntryVoter"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />      </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="processConfigAttribute"</span><span style="color: rgb(0, 0, 255);">&gt;&lt;</span><span style="color: rgb(128, 0, 0);">value</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">ACL_CONTACT_DELETE</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">value</span><span style="color: rgb(0, 0, 255);">&gt;&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />      </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="processDomainObjectClass"</span><span style="color: rgb(0, 0, 255);">&gt;&lt;</span><span style="color: rgb(128, 0, 0);">value</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">sample.contact.Contact</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">value</span><span style="color: rgb(0, 0, 255);">&gt;&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />      </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="aclManager"</span><span style="color: rgb(0, 0, 255);">&gt;&lt;</span><span style="color: rgb(128, 0, 0);">ref </span><span style="color: rgb(255, 0, 0);">local</span><span style="color: rgb(0, 0, 255);">="aclManager"</span><span style="color: rgb(0, 0, 255);">/&gt;&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />      </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="requirePermission"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />        </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">list</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />          </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">ref </span><span style="color: rgb(255, 0, 0);">local</span><span style="color: rgb(0, 0, 255);">="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br />          </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">ref </span><span style="color: rgb(255, 0, 0);">local</span><span style="color: rgb(0, 0, 255);">="org.acegisecurity.acl.basic.SimpleAclEntry.DELETE"</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br />        </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">list</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />      </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />   </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">bean</span><span style="color: rgb(0, 0, 255);">&gt;</span></div>上面第一个配置里有这么一行：sample.contact.ContactManager.delete=ACL_CONTACT_DELETE<br />所以在调用sample.contact.ContactManager.delete这个方法时aclContactDeleteVoter会参与投票，它会获得sample.contact.Contact这个对象（这个对象从delete方法的参数中获得），然后通过aclManager去获得当前用户对该Contact实例的ACL权限，最后拿这个权限与我们需要的权限比对，我们配置需要的权限是org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION和org.acegisecurity.acl.basic.SimpleAclEntry.DELETE。如果我们通过aclManager获得的权限包括这两个配置的权限之一，Voter就投容许票，方法容许调用。如果不包括，那对不起，反对票，AccessDecisionManager就会抛出AccessDeniedException。方法拒绝调用。<br /><b>AclManager的配置</b>：<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">bean </span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="aclManager"</span><span style="color: rgb(255, 0, 0);"> class</span><span style="color: rgb(0, 0, 255);">="org.acegisecurity.acl.AclProviderManager"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />      </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="providers"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />         </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">list</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />            </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">ref </span><span style="color: rgb(255, 0, 0);">local</span><span style="color: rgb(0, 0, 255);">="basicAclProvider"</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br />         </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">list</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />      </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />   </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">bean</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><br />   </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">bean </span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="basicAclProvider"</span><span style="color: rgb(255, 0, 0);"> class</span><span style="color: rgb(0, 0, 255);">="org.acegisecurity.acl.basic.BasicAclProvider"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />      </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="basicAclDao"</span><span style="color: rgb(0, 0, 255);">&gt;&lt;</span><span style="color: rgb(128, 0, 0);">ref </span><span style="color: rgb(255, 0, 0);">local</span><span style="color: rgb(0, 0, 255);">="basicAclExtendedDao"</span><span style="color: rgb(0, 0, 255);">/&gt;&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />   </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">bean</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><br />   </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">bean </span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="basicAclExtendedDao"</span><span style="color: rgb(255, 0, 0);"> class</span><span style="color: rgb(0, 0, 255);">="org.acegisecurity.acl.basic.jdbc.JdbcExtendedDaoImpl"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />      </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="dataSource"</span><span style="color: rgb(0, 0, 255);">&gt;&lt;</span><span style="color: rgb(128, 0, 0);">ref </span><span style="color: rgb(255, 0, 0);">bean</span><span style="color: rgb(0, 0, 255);">="dataSource"</span><span style="color: rgb(0, 0, 255);">/&gt;&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />   </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">bean</span><span style="color: rgb(0, 0, 255);">&gt;</span></div>AclManager是整个ACL中一个很核心的概念，它包含了两个方法AclEntry[] getAcls(Object domainInstance)和<br />AclEntry[] getAcls(Object domainInstance, Authentication authentication)。在了解这两个方法前，我们先了解AclEntry这个对象。AclEntry只是一个接口，系统中一般都是造型为BasicAclEntry。它包括了这个Entry所保护的domainObject instance（这里是Contact），实际它实现上是以AclObjectIdentity来替代这个domainObject的（domainClass+domainObjectId）；它包括了谁（Recipient）拥有这个domainObject instance以及他所对这个domainObject instance的操作权限（mask）。<br />一个domainObject instance对应了多个AclEntry，比如一条通讯录张三可以查看，而李四可以管理，一个Contact instance就对应了两个AclEntry，第一个AclEntry包含信息：所保护的domainObject（Contact）,谁（张三），权限（查看）;第二个AclEntry包含信息：所保护的domainObject（Contact）,谁（李四），权限（管理）。<br />这样AclManager的两个方法就很好理解了getAcls(Object domainInstance)返回所有这个domainInstance所对应的权限信息，<br />getAcls(Object domainInstance, Authentication authentication)在第一个方法返回结果的基础上做了过滤，过滤出和authentication（当前用户）相关的权限信息。如果当前用户是张三，则返回与张三对应的记录。<br /><br />这样Acegi就会拦截业务方法发挥相应的作用，但是在业务方法返回一个List或是单个domainObject instance的时候，同样也是需要把用户没有权限查看的domainObject instance过滤掉的，这时就要用afterInvocationManager了，<b>看配置</b>：<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">bean </span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="afterInvocationManager"</span><span style="color: rgb(255, 0, 0);"> class</span><span style="color: rgb(0, 0, 255);">="org.acegisecurity.afterinvocation.AfterInvocationProviderManager"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />      </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="providers"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />         </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">list</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />            </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">ref </span><span style="color: rgb(255, 0, 0);">local</span><span style="color: rgb(0, 0, 255);">="afterAclRead"</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br />            </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">ref </span><span style="color: rgb(255, 0, 0);">local</span><span style="color: rgb(0, 0, 255);">="afterAclCollectionRead"</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br />         </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">list</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />      </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />   </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">bean</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />   <br />   </span><span style="color: rgb(0, 128, 0);">&lt;!--</span><span style="color: rgb(0, 128, 0);"> Processes AFTER_ACL_COLLECTION_READ configuration settings </span><span style="color: rgb(0, 128, 0);">--&gt;</span><span style="color: rgb(0, 0, 0);"><br />   </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">bean </span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="afterAclCollectionRead"</span><span style="color: rgb(255, 0, 0);"> class</span><span style="color: rgb(0, 0, 255);">="org.acegisecurity.afterinvocation.BasicAclEntryAfterInvocationCollectionFilteringProvider"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />      </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="aclManager"</span><span style="color: rgb(0, 0, 255);">&gt;&lt;</span><span style="color: rgb(128, 0, 0);">ref </span><span style="color: rgb(255, 0, 0);">local</span><span style="color: rgb(0, 0, 255);">="aclManager"</span><span style="color: rgb(0, 0, 255);">/&gt;&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />      </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="requirePermission"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />        </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">list</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />          </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">ref </span><span style="color: rgb(255, 0, 0);">local</span><span style="color: rgb(0, 0, 255);">="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br />          </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">ref </span><span style="color: rgb(255, 0, 0);">local</span><span style="color: rgb(0, 0, 255);">="org.acegisecurity.acl.basic.SimpleAclEntry.READ"</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br />        </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">list</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />      </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />   </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">bean</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />   <br />   </span><span style="color: rgb(0, 128, 0);">&lt;!--</span><span style="color: rgb(0, 128, 0);"> Processes AFTER_ACL_READ configuration settings </span><span style="color: rgb(0, 128, 0);">--&gt;</span><span style="color: rgb(0, 0, 0);"><br />   </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">bean </span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="afterAclRead"</span><span style="color: rgb(255, 0, 0);"> class</span><span style="color: rgb(0, 0, 255);">="org.acegisecurity.afterinvocation.BasicAclEntryAfterInvocationProvider"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />      </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="aclManager"</span><span style="color: rgb(0, 0, 255);">&gt;&lt;</span><span style="color: rgb(128, 0, 0);">ref </span><span style="color: rgb(255, 0, 0);">local</span><span style="color: rgb(0, 0, 255);">="aclManager"</span><span style="color: rgb(0, 0, 255);">/&gt;&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />      </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="requirePermission"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />        </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">list</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />          </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">ref </span><span style="color: rgb(255, 0, 0);">local</span><span style="color: rgb(0, 0, 255);">="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br />          </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">ref </span><span style="color: rgb(255, 0, 0);">local</span><span style="color: rgb(0, 0, 255);">="org.acegisecurity.acl.basic.SimpleAclEntry.READ"</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br />        </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">list</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />      </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />   </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">bean</span><span style="color: rgb(0, 0, 255);">&gt;</span></div>afterAclCollectionRead会对配置AFTER_ACL_COLLECTION_READ的方法进行拦截，这里是sample.contact.ContactManager.getAll方法，它会遍历方法返回的domainObject，然后挨个通过aclManager判断当前用户对domainObject的权限，如果和需要的权限不和，则过滤掉。呵呵，传说中的虎牙子就在此时产生了！<br />afterAclRead则依次类推。<br />参考了ss wiki里相关的文档，特别是差沙和cac的文档，写的相当好。另外acegi的代码也是相当的易读。<br /><img src ="http://www.blogjava.net/RongHao/aggbug/105069.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/RongHao/" target="_blank">ronghao</a> 2007-03-20 19:07 <a href="http://www.blogjava.net/RongHao/archive/2007/03/20/105069.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>对权限分类的补遗</title><link>http://www.blogjava.net/RongHao/archive/2007/03/20/104902.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Tue, 20 Mar 2007 03:04:00 GMT</pubDate><guid>http://www.blogjava.net/RongHao/archive/2007/03/20/104902.html</guid><wfw:comment>http://www.blogjava.net/RongHao/comments/104902.html</wfw:comment><comments>http://www.blogjava.net/RongHao/archive/2007/03/20/104902.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/RongHao/comments/commentRss/104902.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/RongHao/services/trackbacks/104902.html</trackback:ping><description><![CDATA[昨天对现有系统已实现的功能大概的描述了一下，其实里面我觉得最重要的是对客户可能存在的权限需求的分类。这两天也在写关于权限的文档，这里想到了对权限的第六种分类，其实之所以这样分类也是由于具体实现的差异所造成的。<br /><p class="MsoNormal" style="text-indent: 10.55pt;"><b style=""><span style="font-family: 宋体;">六是数据范围操作权限，</span></b><span style="font-family: 宋体;">其实这个是可以和数据范围权限合为一个的。具体的区别在与对已经划分范围的数据再增加操作的权限控制。还是以财务管理为例，部门经理只能查看金额小于</span><span lang="EN-US">1W</span><span style="font-family: 宋体;">的数据；而总经理则没有限制，可以查看所有数据。但是请注意：他们只能对这些数据拥有查看的权限，不能修改或是删除，而财务则拥有修改的权限。在一些情况下可以用<b style="">模块操作权限和数据范围权限</b>的叠加来满足对该权限的需求，但是在权限复杂的情况下，这个权限独立出来是必须的。</span><span lang="EN-US"><o:p></o:p></span></p>

事实上现有系统就是<span style="font-family: 宋体;">用<b style="">模块操作权限和数据范围权限</b>的叠加来满足这部分需求的。<br /><br /></span><img src ="http://www.blogjava.net/RongHao/aggbug/104902.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/RongHao/" target="_blank">ronghao</a> 2007-03-20 11:04 <a href="http://www.blogjava.net/RongHao/archive/2007/03/20/104902.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>权限系统功能说明</title><link>http://www.blogjava.net/RongHao/archive/2007/03/18/104606.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Sun, 18 Mar 2007 14:46:00 GMT</pubDate><guid>http://www.blogjava.net/RongHao/archive/2007/03/18/104606.html</guid><wfw:comment>http://www.blogjava.net/RongHao/comments/104606.html</wfw:comment><comments>http://www.blogjava.net/RongHao/archive/2007/03/18/104606.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/RongHao/comments/commentRss/104606.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/RongHao/services/trackbacks/104606.html</trackback:ping><description><![CDATA[很早就完成了权限系统的编码，这里把一些功能说明贴出来，也希望提提意见。<br /><p class="MsoNormal"><span lang="EN-US"></span><span style="font-family: 宋体;">权限系统基于</span><span lang="EN-US">acegi</span><span style="font-family: 宋体;">框架实现了从前端页面到后台数据全面的控制。在权限控制中，它将权限分成五类：</span><span lang="EN-US">   <br />
  </span><b style=""><span style="font-family: 宋体;">一是系统权限</span></b><span style="font-family: 宋体;">，主要是对模块为单位的权限划分，具体就是用户对该模块可见不可见，能不能对该模块进行再授权的操作。表现在用户界面就是用户登录系统主页面后，可以看到的顶部菜单和左侧</span><span lang="EN-US">outlookbar</span><span style="font-family: 宋体;">菜单的内容控制。作为粒度最大的权限控制，系统实现了</span><span lang="EN-US">web url</span><span style="font-family: 宋体;">的防盗链功能。举例来说，用户新开发的一个叫车辆管理的模块，配置在</span><span lang="EN-US"><a href="http://localhost/business/carmanage.action%E7%9A%84url">http://localhost/business/carmanage.action<span style="font-family: 宋体;" lang="EN-US"><span lang="EN-US">的</span></span>url</a></span><span style="font-family: 宋体;">下，当对这个模块的权限加以控制后，直接在浏览器中键入</span><span lang="EN-US"><a href="http://localhost/business/carmanage.action">http://localhost/business/carmanage.action</a></span><span style="font-family: 宋体;">同样是无法访问的，而不仅仅是界面内容的屏蔽。</span><span lang="EN-US"><br />
  </span><b style=""><span style="font-family: 宋体;">二是模块操作权限</span></b><span style="font-family: 宋体;">，在对整个模块的权限做出控制后，这里继续对模块的浏览、增加，修改，删除的操作权限做出控制，也可以理解为对象权限</span><span lang="EN-US"> </span><span style="font-family: 宋体;">。还是以车辆管理为例，不同的人员对这个模块的操作是不同的，有些用户可以新增，删除车辆；而有些用户则只是可以对车辆的情况查看不能修改。通过系统提供的一套</span><span lang="EN-US">web </span><span style="font-family: 宋体;">标签，页面可以根据用户不同的操作权限屏蔽相应的功能按键。例如删除，新增按键。用户绕过页面直接操作相应业务方法同样也做到了严格的控制，没有权限的访问会被拒绝同时记入日志。</span><span lang="EN-US">  <br />
  </span><b style=""><span style="font-family: 宋体;">三是数据范围权限</span></b><span style="font-family: 宋体;">，又可以叫做对象实例级权限。事实上不是每个用户都可以看到所有记录的。以财务管理为例，部门经理只能查看金额小于</span><span lang="EN-US">1W</span><span style="font-family: 宋体;">的数据；而总经理则没有限制。</span><span style="font-family: 宋体;">权限系统对这部分权限也做出了全面的控制，可以根据数据类型，相应字段数值范围做出控制。</span><span lang="EN-US"><br />
  </span><b style=""><span style="font-family: 宋体;">四是单条数据</span><span lang="EN-US">ACL</span></b><b style=""><span style="font-family: 宋体;">权限</span></b><span style="font-family: 宋体;">，为了满足更严格的数据权限要求，</span><span style="font-family: 宋体;">权限系统对数据实现了单条数据的</span><span lang="EN-US">ACL</span><span style="font-family: 宋体;">权限，具体说就是对每条数据都实现了权限控制，每条数据都有一到多条权限数据与其对应。以个人通讯录为例，每个用户都维护自己的一个通讯录，这些数据都只是对本人可见，其他人不可见。但用户可以对这些数据做出授权，将某条联系方式以授权的方式共享给其他人，并赋予不同的权限，包括拥有，修改，删除，浏览四种权限。</span></p><p class="MsoNormal" style="text-indent: 10.55pt;"><b style=""><span style="font-family: 宋体;">五是数据字段权限</span></b><span style="font-family: 宋体;">，通过</span><span lang="EN-US">xml</span><span style="font-family: 宋体;">配置，</span><span lang="EN-US">系统</span><span style="font-family: 宋体;">保证了用户的最小粒度的权限控制。每条业务数据权限可以精确控制到每一个字段。包括单个字段的可否浏览以及可否修改。保证了敏感信息的安全性。</span></p><p class="MsoNormal" style="text-indent: 10.5pt;"><span lang="EN-US"><br /></span><span style="font-family: 宋体;">授权，作为权限系统的重要部分，</span><span lang="EN-US">系统</span><span style="font-family: 宋体;">提供了相当方便的操作体验。以树状的方式展现权限主体（用户，角色，部门）以及资源，方便，直接，一目了然。区别与传统的</span><span lang="EN-US">RBAC</span><span style="font-family: 宋体;">模型，权限不仅仅可以分配给角色，也可以分配给部门和用户。实际的权限是这三者权限的叠加，最大限度的方便用户操作。考虑到用户的扩展，系统提供两个权限继承规则接口，用户可以自定义权限继承的规则。例如，部门</span><span lang="EN-US">A</span><span style="font-family: 宋体;">下有部门</span><span lang="EN-US">A1</span><span style="font-family: 宋体;">，部门</span><span lang="EN-US">A</span><span style="font-family: 宋体;">的权限是否由部门</span><span lang="EN-US">A1</span><span style="font-family: 宋体;">继承。</span></p><span style="font-size: 10.5pt; font-family: 宋体;">整个权限系统的数据都建立在系统统一的缓存管理之上，用户登录后，其权限信息即被缓存，保证系统的效率</span><br /><img src ="http://www.blogjava.net/RongHao/aggbug/104606.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/RongHao/" target="_blank">ronghao</a> 2007-03-18 22:46 <a href="http://www.blogjava.net/RongHao/archive/2007/03/18/104606.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>对Acegi ACL扩展的构想</title><link>http://www.blogjava.net/RongHao/archive/2006/12/14/87634.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Thu, 14 Dec 2006 02:20:00 GMT</pubDate><guid>http://www.blogjava.net/RongHao/archive/2006/12/14/87634.html</guid><wfw:comment>http://www.blogjava.net/RongHao/comments/87634.html</wfw:comment><comments>http://www.blogjava.net/RongHao/archive/2006/12/14/87634.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/RongHao/comments/commentRss/87634.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/RongHao/services/trackbacks/87634.html</trackback:ping><description><![CDATA[
		<p>数据权限分为两种，一种是数据范围权限，一种是具体到每一条数据的权限。前一种可以通过动态构建SQL解决；后一种<br />似乎必须通过ACL不可。于是就想对Acegi ACL做一个通用的扩展。以通讯录为例<br />先看一个总的配置<br />  &lt;bean id="contactManagerSecurityInterceptor" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor"&gt;<br />      &lt;property name="authenticationManager"&gt;&lt;ref bean="authenticationManager"/&gt;&lt;/property&gt;<br />      &lt;property name="accessDecisionManager"&gt;&lt;ref local="aclDecisionManager"/&gt;&lt;/property&gt;<br />      &lt;property name="afterInvocationManager"&gt;&lt;ref local="afterInvocationManager"/&gt;&lt;/property&gt;<br />      &lt;property name="objectDefinitionSource"&gt;<br />         &lt;value&gt;<br />            com.ronghao.acltest.services.ContactService.saveContact=AFTER_ACL_CREAT<br />            com.ronghao.acltest.services.ContactService.getAllContacts=AFTER_ACL_COLLECTION_READ<br />            com.ronghao.acltest.services.ContactService.getContact=AFTER_ACL_READ<br />         &lt;/value&gt;<br />      &lt;/property&gt;<br />   &lt;/bean&gt;<br />扩展一、当你增加一条记录的同时向ACL表里插入权限信息 这个SS已经做到了这一点<br />  ss有一个接口标示哪些doamin需要acl保护 AclDomainAware<br />  这里再扩展一个基类 ，目的很简单当读出数据时附加上权限信息<br />  public  class BasicAclDomain implements AclDomainAware {</p>
		<p>    private int mask; //权限</p>
		<p>    public int getMask() {<br />        return mask;<br />    }</p>
		<p>    public void setMask(int mask) {<br />        this.mask = mask;<br />    }<br />  }<br />  <br />  public class Contact extends BasicAclDomain <br />扩展二、读取列表时进行数据的过滤，原来的acegi在ACL的集合后处理会造成分页产生虎牙子<br />     这里采用前拦截，在acl表里增加一个className字段,里面放上PO的类名,这样可以缩小<br />     数据查询范围.实际在读取集合时,是先到acl表里完成分页,然后获得对Contact的real id list <br />     然后拦截实际DAO方法,动态改变SQL成select * from real_data where id in ( {real id list} )的形式,这样就OK了,<br />     分页实际是对acl表里相应记录的'分页'.比如说取第10条到20条,实际是取acl表里相应记录的第10条到20条来动态改变SQL <br />     这个可以写一个专门被用来拦截的类 SecurityDAO 方法findByPageACL(query, page)，ContactServiceImpl中getAllContacts<br />     方法强制调用该方法<br />扩展三、后拦截。这里AFTER_ACL_COLLECTION_READ和AFTER_ACL_READ的目的就很简单了，因为他们不再进行数据过 滤， 他们只是把用户对每条记录的mask取最大权限就OK，然后往PO里setMask。这样PO带了权限信息到页面上就非常好处理了。比如button的显示等等<br />扩展四、封装AclService,对单条记录的ACL权限管理。比如增加权限、修改权限、删除权限。这个acegi的最新1.0.3已经开始加入。<br />具体在实现中感觉acl的vote完全是鸡肋，全部不用。另外在扩展二中如果用户数据要实现数据库排序就比较困难。所以就有了还未实现的构想：<br />一、PO创建向ACL表里插入权限信息时可以配置不同的策略：比如通讯录创建一条新信息只能创建者可以看并管理，而你往请假表里插一条新信息后，不仅你了，你的上司也可以同时看到。（这个还是比较easy）<br />二、用户数据要实现数据库排序。需要在ACL_OBJECT_IDENTITY里增加几个额外的字段，把po相应的排序字段同步更新到ACL表中。什么？不好做？写配置文件啊！再对PO的update进行后拦截。<br />想法就这样。实现？？</p>
<img src ="http://www.blogjava.net/RongHao/aggbug/87634.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/RongHao/" target="_blank">ronghao</a> 2006-12-14 10:20 <a href="http://www.blogjava.net/RongHao/archive/2006/12/14/87634.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>acegi整合CAS</title><link>http://www.blogjava.net/RongHao/archive/2006/08/29/66389.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Tue, 29 Aug 2006 04:31:00 GMT</pubDate><guid>http://www.blogjava.net/RongHao/archive/2006/08/29/66389.html</guid><wfw:comment>http://www.blogjava.net/RongHao/comments/66389.html</wfw:comment><comments>http://www.blogjava.net/RongHao/archive/2006/08/29/66389.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/RongHao/comments/commentRss/66389.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/RongHao/services/trackbacks/66389.html</trackback:ping><description><![CDATA[acegi内置了对CAS的支持。这里的CAS是3.0。建立CAS server是一个比较简单的事情。CAS server就是一个标准的war文件，把它发布就可以运行。需要做的仅仅是调整登陆和其他一些页面。先了解一下CAS如何实现SSO。<br />例子：原有系统A和系统B，现在在它们之间做SSO。<br />很显然，系统A和B都是CAS client。首先是访问系统A，干掉A的登陆页面，在A的入口判断有没有Ticket(票据），如果没有则重定向到CAS server，在CAS server提供Credential（大多数情况就是用户名和密码）。CAS server的作用非常简单：就是来验证用户密码。正确，则发送Ticket。CAS有5种Ticket，分别是TGC(通过cookie发送的ticket），ST（Service Ticket),PGT,PGTIOU,PT。其中PGT,PGTIOU,PT属于代理ticket，这里不作讨论。具体可以参考<br /><a href="/openssl/archive/2006/04/26/SSO_CASProxy.html">http://www.blogjava.net/openssl/archive/2006/04/26/SSO_CASProxy.html</a><br />TGC和ST的关系可以打个比方：<br />我去中央电视塔去玩，结果发现地下还有个海底世界。SSO前我是这么玩的：先去电视塔买张门票，玩完了；再去海底世界买张门票，玩完了。发现真累，两个景点这么近还要买两次门票，就不能搞个通票吗？于是就SSO。于是这样：我先去电视塔，门卫告诉我你不能进去要买票，于是把我送到通票售票处（CAS server）买票（登录），买吧，于是给了我两张票，注意，是两张，一张发到我手里，上面写着仅限电视塔使用（ST）；靠，不是通票吗，咋仅限电视塔使用？别急，还有一张票（TGC）通过cookie发送你看不见。人家说了保证没问题，我咋办，这是人家的规矩，那就先去玩吧。出了电视塔我直扑海底世界，<br />门卫说要海底世界票，不会吧，我买的通票啊，门卫说不着急，又把我送回通票售票处（CAS server），通票售票处（CAS server）一看，发现我有TGC，嘿嘿，这家伙买过票了不用再买（不用再登录），于是换我一张票（ST）上面写着仅限海底世界使用，于是我就拿着这张票又去海底世界了。于是我明白了啥是SSO了，不就是把买票改成换票了吗？<br />比方完了，最开始的例子也就不往下继续了。需要注意的是系统A和B整合SSO需要把A、B的用户密码集中管理，你说A中我的用户名是张三，B中是李四，SSO能不能帮我自动识别，回答是不行的。<br />继续Acegi的整合。<br />CAS server是做用户密码验证，具体的权限授权的工作还是在各个单个系统里，也不应该交给它管。做用户密码验证需要AuthenticationHandler。这个具体就是根据Credential返回一个boolean值来判断你输入的用户密码正不正确。acegi提供了一个实现。<br />以一个典型的web访问来说明整个过程<br />1、用户访问一个受acegi安全保护的页面或业务方法；<br />2、用户没有登陆的话显然会抛出AuthenticationException<br />3、配置exceptionTranslationFilter捕获这个异常重定向到CAS server登陆页面<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /><span style="color: rgb(0, 0, 0);">       </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">bean </span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="exceptionTranslationFilter"</span><span style="color: rgb(255, 0, 0);"> class</span><span style="color: rgb(0, 0, 255);">="org.acegisecurity.ui.ExceptionTranslationFilter"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />            </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="authenticationEntryPoint"</span><span style="color: rgb(0, 0, 255);">&gt;&lt;</span><span style="color: rgb(128, 0, 0);">ref </span><span style="color: rgb(255, 0, 0);">local</span><span style="color: rgb(0, 0, 255);">="casProcessingFilterEntryPoint"</span><span style="color: rgb(0, 0, 255);">/&gt;&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">bean</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">bean </span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="casProcessingFilterEntryPoint"</span><span style="color: rgb(255, 0, 0);"> class</span><span style="color: rgb(0, 0, 255);">="org.acegisecurity.ui.cas.CasProcessingFilterEntryPoint"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />            </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="loginUrl"</span><span style="color: rgb(0, 0, 255);">&gt;&lt;</span><span style="color: rgb(128, 0, 0);">value</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">https://my.company.com/cas/login</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">value</span><span style="color: rgb(0, 0, 255);">&gt;&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />            </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="serviceProperties"</span><span style="color: rgb(0, 0, 255);">&gt;&lt;</span><span style="color: rgb(128, 0, 0);">ref </span><span style="color: rgb(255, 0, 0);">local</span><span style="color: rgb(0, 0, 255);">="serviceProperties"</span><span style="color: rgb(0, 0, 255);">/&gt;&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">bean</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">bean </span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="serviceProperties"</span><span style="color: rgb(255, 0, 0);"> class</span><span style="color: rgb(0, 0, 255);">="org.acegisecurity.ui.cas.ServiceProperties"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />            </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="service"</span><span style="color: rgb(0, 0, 255);">&gt;&lt;</span><span style="color: rgb(128, 0, 0);">value</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">https://server.company.com/myapp/j_acegi_cas_security_check</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">value</span><span style="color: rgb(0, 0, 255);">&gt;&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />            </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="sendRenew"</span><span style="color: rgb(0, 0, 255);">&gt;&lt;</span><span style="color: rgb(128, 0, 0);">value</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">false</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">value</span><span style="color: rgb(0, 0, 255);">&gt;&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">bean</span><span style="color: rgb(0, 0, 255);">&gt;</span></div>serviceProperties里的service属性即在CAS server登陆完毕后由CAS server重定向回来的页面<br />  <a href="https://my.company.com/cas/login?service=https%3A%2F%2Fserver.company.com%2Fmyapp%2Fj_acegi_cas_security_check">https://my.company.com/cas/login?service=https%3A%2F%2Fserver.company.com%2Fmyapp%2Fj_acegi_cas_security_check</a><br />4、CAS server检查是否有TGC ，没有则登陆，登陆后返回。这里屁股后面跟着的即ST，TGC通过cookie一并发送到客户端。<br />   <a href="https://server.company.com/myapp/j_acegi_cas_security_check?ticket=ST-0-jhsdfguwgeds">https://server.company.com/myapp/j_acegi_cas_security_check?ticket=ST-0-jhsdfguwgeds</a><br />5、配置casProcessingFilter来处理返回ST（和以前的authenticationProcessingFilter比较类似）<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /><span style="color: rgb(0, 0, 0);">   </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">bean </span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="casProcessingFilter"</span><span style="color: rgb(255, 0, 0);"> class</span><span style="color: rgb(0, 0, 255);">="org.acegisecurity.ui.cas.CasProcessingFilter"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="authenticationManager"</span><span style="color: rgb(0, 0, 255);">&gt;&lt;</span><span style="color: rgb(128, 0, 0);">ref </span><span style="color: rgb(255, 0, 0);">local</span><span style="color: rgb(0, 0, 255);">="authenticationManager"</span><span style="color: rgb(0, 0, 255);">/&gt;&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="authenticationFailureUrl"</span><span style="color: rgb(0, 0, 255);">&gt;&lt;</span><span style="color: rgb(128, 0, 0);">value</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">/casfailed.jsp</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">value</span><span style="color: rgb(0, 0, 255);">&gt;&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="defaultTargetUrl"</span><span style="color: rgb(0, 0, 255);">&gt;&lt;</span><span style="color: rgb(128, 0, 0);">value</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">value</span><span style="color: rgb(0, 0, 255);">&gt;&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="filterProcessesUrl"</span><span style="color: rgb(0, 0, 255);">&gt;&lt;</span><span style="color: rgb(128, 0, 0);">value</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">/j_acegi_cas_security_check</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">value</span><span style="color: rgb(0, 0, 255);">&gt;&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />    </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">bean</span><span style="color: rgb(0, 0, 255);">&gt;</span></div>6、配置authenticationManager<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /><span style="color: rgb(0, 0, 0);">   </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">bean </span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="authenticationManager"</span><span style="color: rgb(255, 0, 0);"> class</span><span style="color: rgb(0, 0, 255);">="org.acegisecurity.providers.ProviderManager"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />      </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="providers"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />         </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">list</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />            </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">ref </span><span style="color: rgb(255, 0, 0);">local</span><span style="color: rgb(0, 0, 255);">="casAuthenticationProvider"</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />         </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">list</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />      </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />   </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">bean</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />   <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />  </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">bean </span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="casAuthenticationProvider"</span><span style="color: rgb(255, 0, 0);"> class</span><span style="color: rgb(0, 0, 255);">="org.acegisecurity.providers.cas.CasAuthenticationProvider"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="casAuthoritiesPopulator"</span><span style="color: rgb(0, 0, 255);">&gt;&lt;</span><span style="color: rgb(128, 0, 0);">ref </span><span style="color: rgb(255, 0, 0);">local</span><span style="color: rgb(0, 0, 255);">="casAuthoritiesPopulator"</span><span style="color: rgb(0, 0, 255);">/&gt;&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="casProxyDecider"</span><span style="color: rgb(0, 0, 255);">&gt;&lt;</span><span style="color: rgb(128, 0, 0);">ref </span><span style="color: rgb(255, 0, 0);">local</span><span style="color: rgb(0, 0, 255);">="casProxyDecider"</span><span style="color: rgb(0, 0, 255);">/&gt;&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="ticketValidator"</span><span style="color: rgb(0, 0, 255);">&gt;&lt;</span><span style="color: rgb(128, 0, 0);">ref </span><span style="color: rgb(255, 0, 0);">local</span><span style="color: rgb(0, 0, 255);">="casProxyTicketValidator"</span><span style="color: rgb(0, 0, 255);">/&gt;&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="statelessTicketCache"</span><span style="color: rgb(0, 0, 255);">&gt;&lt;</span><span style="color: rgb(128, 0, 0);">ref </span><span style="color: rgb(255, 0, 0);">local</span><span style="color: rgb(0, 0, 255);">="statelessTicketCache"</span><span style="color: rgb(0, 0, 255);">/&gt;&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="key"</span><span style="color: rgb(0, 0, 255);">&gt;&lt;</span><span style="color: rgb(128, 0, 0);">value</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">my_password_for_this_auth_provider_only</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">value</span><span style="color: rgb(0, 0, 255);">&gt;&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />    </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">bean</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"> </span></div>具体作用的是casAuthenticationProvider，casAuthenticationProvider通过 casProxyTicketValidator来校验ST<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /><span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">bean </span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="casProxyTicketValidator"</span><span style="color: rgb(255, 0, 0);"> class</span><span style="color: rgb(0, 0, 255);">="org.acegisecurity.providers.cas.ticketvalidator.CasProxyTicketValidator"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="casValidate"</span><span style="color: rgb(0, 0, 255);">&gt;&lt;</span><span style="color: rgb(128, 0, 0);">value</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">https://my.company.com/cas/proxyValidate</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">value</span><span style="color: rgb(0, 0, 255);">&gt;&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">property </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="serviceProperties"</span><span style="color: rgb(0, 0, 255);">&gt;&lt;</span><span style="color: rgb(128, 0, 0);">ref </span><span style="color: rgb(255, 0, 0);">local</span><span style="color: rgb(0, 0, 255);">="serviceProperties"</span><span style="color: rgb(0, 0, 255);">/&gt;&lt;/</span><span style="color: rgb(128, 0, 0);">property</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />    </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">bean</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"> </span></div>casProxyTicketValidator又具体实现调用了CAS Client library里的ProxyTicketValidator校验ST，ProxyTicketValidator 就比较有意思了，它做了个HTTPS请求CAS server，结果还是CAS server来校验ST（绕了一大圈）<br /> <a href="https://my.company.com/cas/proxyValidate?service=https%3A%2F%2Fserver.company.com%2Fmyapp%2Fj_acegi_cas_security_check">https://my.company.com/cas/proxyValidate?service=https%3A%2F%2Fserver.company.com%2Fmyapp%2Fj_acegi_cas_security_check</a><br /> 重新回到CAS server，它接受到这个HTTPS请求，检查ST是否与对这个service发行的ST吻合，吻合的话CAS server就会发回一个肯定的XML回复，里面包含了用户名（username)。剩下的就EASY了，casProxyTicketValidator解析XML，casProxyDecider处理代理，casAuthoritiesPopulator根据解析后的XML获得user，最后就是casAuthenticationProvider构造Authentication（这里是CasAuthenticationToken）<br />7、重新回到casProcessingFilter，它将Authentication放入HttpSession<br />这样就完成了整个过程<img src ="http://www.blogjava.net/RongHao/aggbug/66389.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/RongHao/" target="_blank">ronghao</a> 2006-08-29 12:31 <a href="http://www.blogjava.net/RongHao/archive/2006/08/29/66389.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>agegi整合小经验</title><link>http://www.blogjava.net/RongHao/archive/2006/08/03/61475.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Thu, 03 Aug 2006 02:45:00 GMT</pubDate><guid>http://www.blogjava.net/RongHao/archive/2006/08/03/61475.html</guid><wfw:comment>http://www.blogjava.net/RongHao/comments/61475.html</wfw:comment><comments>http://www.blogjava.net/RongHao/archive/2006/08/03/61475.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/RongHao/comments/commentRss/61475.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/RongHao/services/trackbacks/61475.html</trackback:ping><description><![CDATA[在web.xml中一般我们这样配置：<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">filter</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">mapping</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />        </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">filter</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">name</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">Acegi Filter Chain Proxy</span><span style="color: rgb(0, 0, 0);">&lt;/</span><span style="color: rgb(0, 0, 0);">filter</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">name</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />        </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">url</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">pattern</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 128, 0);">/*</span><span style="color: rgb(0, 128, 0);">&lt;/url-pattern&gt;<br />    &lt;/filter-mapping&gt;</span></div>这样agegi就对所有的url进行了过滤检查，以一个显示树状菜单为例，它甚至对页面上的每一个图片连接都进行了检查，实际上这是完全没有必要，可以这样：<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">filter</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">mapping</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />        </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">filter</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">name</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">Acegi Filter Chain Proxy</span><span style="color: rgb(0, 0, 0);">&lt;/</span><span style="color: rgb(0, 0, 0);">filter</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">name</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />        </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">url</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">pattern</span><span style="color: rgb(0, 0, 0);">&gt;*</span><span style="color: rgb(0, 0, 0);">.action</span><span style="color: rgb(0, 0, 0);">&lt;/</span><span style="color: rgb(0, 0, 0);">url</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">pattern</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />    </span><span style="color: rgb(0, 0, 0);">&lt;/</span><span style="color: rgb(0, 0, 0);">filter</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">mapping</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><br />    </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">filter</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">mapping</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />        </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">filter</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">name</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">Acegi Filter Chain Proxy</span><span style="color: rgb(0, 0, 0);">&lt;/</span><span style="color: rgb(0, 0, 0);">filter</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">name</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />        </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">url</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">pattern</span><span style="color: rgb(0, 0, 0);">&gt;*</span><span style="color: rgb(0, 0, 0);">.ftl</span><span style="color: rgb(0, 0, 0);">&lt;/</span><span style="color: rgb(0, 0, 0);">url</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">pattern</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />    </span><span style="color: rgb(0, 0, 0);">&lt;/</span><span style="color: rgb(0, 0, 0);">filter</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">mapping</span><span style="color: rgb(0, 0, 0);">&gt;</span></div>呵呵，检查范围缩小了，可是登陆时系统报404错误，找不到/j_acegi_security_check，因为/j_acegi_security_check这个路径是agegi自己的，所以再增加一行拦截过滤就OK<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">filter</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">mapping</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />        </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">filter</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">name</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">Acegi Filter Chain Proxy</span><span style="color: rgb(0, 0, 0);">&lt;/</span><span style="color: rgb(0, 0, 0);">filter</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">name</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />        </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">url</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">pattern</span><span style="color: rgb(0, 0, 0);">&gt;/</span><span style="color: rgb(0, 0, 0);">j_acegi_security_check</span><span style="color: rgb(0, 0, 0);">&lt;/</span><span style="color: rgb(0, 0, 0);">url</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">pattern</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />    </span><span style="color: rgb(0, 0, 0);">&lt;/</span><span style="color: rgb(0, 0, 0);">filter</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">mapping</span><span style="color: rgb(0, 0, 0);">&gt;</span></div><img src ="http://www.blogjava.net/RongHao/aggbug/61475.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/RongHao/" target="_blank">ronghao</a> 2006-08-03 10:45 <a href="http://www.blogjava.net/RongHao/archive/2006/08/03/61475.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>乱弹权限系统续二</title><link>http://www.blogjava.net/RongHao/archive/2006/07/06/56998.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Thu, 06 Jul 2006 09:47:00 GMT</pubDate><guid>http://www.blogjava.net/RongHao/archive/2006/07/06/56998.html</guid><wfw:comment>http://www.blogjava.net/RongHao/comments/56998.html</wfw:comment><comments>http://www.blogjava.net/RongHao/archive/2006/07/06/56998.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/RongHao/comments/commentRss/56998.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/RongHao/services/trackbacks/56998.html</trackback:ping><description><![CDATA[
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<b style="">
						<span style="" lang="EN-US">
								<span style="">一、<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">             </span></span>
						</span>
				</b>
				<b style="">
						<span style="font-family: 宋体;">考虑实现</span>
						<span lang="EN-US">
								<o:p>
								</o:p>
						</span>
				</b>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt; text-indent: -18pt;">
				<span style="" lang="EN-US">
						<span style="">1、<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">  </span></span>
				</span>
				<span style="font-family: 宋体;">系统权限考虑继续采用原先实现方式，在构造功能树和树状菜单时作出权限判断；</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt; text-indent: -18pt;">
				<span style="" lang="EN-US">
						<span style="">2、<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">  </span></span>
				</span>
				<span style="font-family: 宋体;">数据库操作权限考虑应用</span>
				<span lang="EN-US">Acegi</span>
				<span style="font-family: 宋体;">扩展，在业务层对相应的浏览</span>
				<span lang="EN-US">/</span>
				<span style="font-family: 宋体;">增加</span>
				<span lang="EN-US">/</span>
				<span style="font-family: 宋体;">修改</span>
				<span lang="EN-US">/</span>
				<span style="font-family: 宋体;">删除的业务方法进行拦截；</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt; text-indent: -18pt;">
				<span style="" lang="EN-US">
						<span style="">3、<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">  </span></span>
				</span>
				<span style="font-family: 宋体;">行级数据权限考虑采用</span>
				<span lang="EN-US">AOP</span>
				<span style="font-family: 宋体;">的方式在用户访问相关资源时根据用户权限动态构造</span>
				<span lang="EN-US">SQL</span>
				<span style="font-family: 宋体;">注入到业务方法里，再由业务方法传递到</span>
				<span lang="EN-US">DAO</span>
				<span style="font-family: 宋体;">里；</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt; text-indent: -18pt;">
				<span style="" lang="EN-US">
						<span style="">4、<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">  </span></span>
				</span>
				<span style="font-family: 宋体;">列级数据权限考虑做入页面，这里不再讨论。</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt; text-indent: -18pt;">
				<span style="" lang="EN-US">
						<span style="">5、<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">  </span></span>
				</span>
				<span style="font-family: 宋体;">大集中模式下的权限管理，本质也是行级数据权限，即在每次数据访问时都需要强制判断用户所属部门</span>
				<span lang="EN-US">Group</span>
				<span style="font-family: 宋体;">。<br /></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt;">
				<span style="" lang="EN-US">
						<span style="">
								<font face="Times New Roman">一、</font>
						</span>
				</span>
				<b style="">
						<span style="font-family: 宋体;">权限管理详细解决方案</span>
				</b>
				<span lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">用户、用户组、角色设计如下：<br /><img alt="Image00000.bmp" src="http://www.blogjava.net/images/blogjava_net/ronghao/Image00000.bmp" border="0" height="345" width="470" /><br /></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span lang="EN-US">
						<v:shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600">
								<v:stroke joinstyle="miter">
								</v:stroke>
								<v:formulas>
										<v:f eqn="if lineDrawn pixelLineWidth 0">
										</v:f>
										<v:f eqn="sum @0 1 0">
										</v:f>
										<v:f eqn="sum 0 0 @1">
										</v:f>
										<v:f eqn="prod @2 1 2">
										</v:f>
										<v:f eqn="prod @3 21600 pixelWidth">
										</v:f>
										<v:f eqn="prod @3 21600 pixelHeight">
										</v:f>
										<v:f eqn="sum @0 0 1">
										</v:f>
										<v:f eqn="prod @6 1 2">
										</v:f>
										<v:f eqn="prod @7 21600 pixelWidth">
										</v:f>
										<v:f eqn="sum @8 21600 0">
										</v:f>
										<v:f eqn="prod @7 21600 pixelHeight">
										</v:f>
										<v:f eqn="sum @10 21600 0">
										</v:f>
								</v:formulas>
								<v:path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f">
								</v:path>
								<o:lock aspectratio="t" v:ext="edit">
								</o:lock>
						</v:shapetype>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span lang="EN-US">
						<font face="Times New Roman">Principal</font>
				</span>
				<span style="font-family: 宋体;">即为权限主体</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt; text-indent: -18pt;">
				<span style="" lang="EN-US">
						<span style="">
								<font face="Times New Roman">1、<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"><font size="3">  </font></span></font>
						</span>
				</span>
				<span style="font-family: 宋体;">系统权限授权</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span lang="EN-US">
						<font face="Times New Roman">web</font>
				</span>
				<span style="font-family: 宋体;">页面：</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">页面上显示两棵树：左侧显示用户、用户组和角色树，右侧显示功能模块树，功能模块树的节点上跟两个复选框，分别是可见</span>
				<span lang="EN-US">
						<font face="Times New Roman">/</font>
				</span>
				<span style="font-family: 宋体;">可再授权。点击用户、用户组和角色树上的节点对相应权限主体进行授权。</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">很显然可再授权权限包含可见权限。</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">数据库实现：</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">用</span>
				<span lang="EN-US">
						<font face="Times New Roman">ACL</font>
				</span>
				<span style="font-family: 宋体;">实现，表设计如下：</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">资源</span>
				<span lang="EN-US">
						<font face="Times New Roman">ID</font>
				</span>
				<span style="font-family: 宋体;">，权限主体</span>
				<span lang="EN-US">
						<font face="Times New Roman">ID</font>
				</span>
				<span style="font-family: 宋体;">，权限主体</span>
				<span lang="EN-US">
						<font face="Times New Roman">TYPE</font>
				</span>
				<span style="font-family: 宋体;">，资源</span>
				<span lang="EN-US">
						<font face="Times New Roman">TYPE</font>
				</span>
				<span style="font-family: 宋体;">，资源操作权限，条件查询语句</span>
				<span lang="EN-US">
						<font face="Times New Roman">queryStr</font>
				</span>
				<span style="font-family: 宋体;">。</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">说明：</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">权限主体</span>
				<span lang="EN-US">
						<font face="Times New Roman">TYPE<span style="">  </span></font>
				</span>
				<span style="font-family: 宋体;">三种：</span>
				<span lang="EN-US">
						<font face="Times New Roman">user/group/role</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">资源</span>
				<span lang="EN-US">
						<font face="Times New Roman">TYPE<span style="">    </span><span style="">     </span></font>
				</span>
				<span style="font-family: 宋体;">两种：</span>
				<span lang="EN-US">
						<font face="Times New Roman">function/method<span style="">  </span></font>
				</span>
				<span style="font-family: 宋体;">此时对系统权限来说是</span>
				<span lang="EN-US">
						<font face="Times New Roman">function</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">条件查询语句</span>
				<span lang="EN-US">
						<font face="Times New Roman">queryStr<span style="">    </span></font>
				</span>
				<span style="font-family: 宋体;">数据范围控制</span>
				<span lang="EN-US">
						<span style="">
								<font face="Times New Roman">  </font>
						</span>
				</span>
				<span style="font-family: 宋体;">此时对系统权限该字段无效</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">对象：<br /><img alt="Image00002.bmp" src="http://www.blogjava.net/images/blogjava_net/ronghao/Image00002.bmp" border="0" height="188" width="363" /><br /></span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span lang="EN-US">
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">用户保存授权信息时，先删除该权限主体</span>
				<span lang="EN-US">
						<font face="Times New Roman">ID</font>
				</span>
				<span style="font-family: 宋体;">的授权记录，再更新。</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt; text-indent: -18pt;">
				<span style="" lang="EN-US">
						<span style="">
								<font face="Times New Roman">2、<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"><font size="3">  </font></span></font>
						</span>
				</span>
				<span style="font-family: 宋体;">数据库操作权限授权</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">这里引入一个新的对象：数据库操作资源对象</span>
				<span lang="EN-US">
						<font face="Times New Roman">
								<span style="">  </span>DataResource</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">表设计如下：</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span lang="EN-US">
						<font face="Times New Roman">ID</font>
				</span>
				<span style="font-family: 宋体;">，</span>
				<span lang="EN-US">
						<font face="Times New Roman">NAME</font>
				</span>
				<span style="font-family: 宋体;">，</span>
				<span lang="EN-US">
						<font face="Times New Roman">parentId</font>
				</span>
				<span style="font-family: 宋体;">，</span>
				<span lang="EN-US">
						<font face="Times New Roman">resStr</font>
				</span>
				<span style="font-family: 宋体;">，</span>
				<span lang="EN-US">
						<font face="Times New Roman">resType</font>
				</span>
				<span style="font-family: 宋体;">，</span>
				<span lang="EN-US">
						<font face="Times New Roman">desc</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">说明如下：</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span lang="EN-US">
						<font face="Times New Roman">ID</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span lang="EN-US">
						<font face="Times New Roman">NAME </font>
				</span>
				<span style="font-family: 宋体;">资源名称</span>
				<font face="Times New Roman">
				</font>
				<span style="font-family: 宋体;">例如：新增用户</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span lang="EN-US">
						<font face="Times New Roman">parentId</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span lang="EN-US">
						<font face="Times New Roman">resStr<span style="">  </span></font>
				</span>
				<span style="font-family: 宋体;">业务方法地址</span>
				<font face="Times New Roman">
				</font>
				<span style="font-family: 宋体;">例如：</span>
				<span lang="EN-US">
						<font face="Times New Roman">com.way.sevice.UserService.addUser</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span lang="EN-US">
						<font face="Times New Roman">resType </font>
				</span>
				<span style="font-family: 宋体;">资源类型，分两种：</span>
				<span lang="EN-US">
						<font face="Times New Roman">abstract/detail<span style="">  </span></font>
				</span>
				<span style="font-family: 宋体;">抽象</span>
				<span lang="EN-US">
						<font face="Times New Roman">/</font>
				</span>
				<span style="font-family: 宋体;">具体</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span lang="EN-US">
						<font face="Times New Roman">desc<span style="">  </span></font>
				</span>
				<span style="font-family: 宋体;">描述说明</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">例子：</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">对用户管理进行数据库操作权限授权</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">新建“用户管理”做父节点，选择资源类型为“抽象”</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">在“用户管理”下再依次新增“新增用户”、“浏览用户”、“修改用户”、“删除用户”四个子节点，选择资源类型为“具体”</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">如果系统自己来判断存储就是叶子节点是“具体”，其他为“抽象”</span>
				<span lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span lang="EN-US">
						<font face="Times New Roman">web</font>
				</span>
				<span style="font-family: 宋体;">页面：</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">页面上显示两棵树：左侧显示用户、用户组和角色树，右侧显示数据库操作资源对象树，数据库操作资源对象树的叶子节点的一级父节点上跟一个数据范围限定</span>
				<span lang="EN-US">
						<font face="Times New Roman">button</font>
				</span>
				<span style="font-family: 宋体;">，点击后弹出窗口输入限定条件；叶子节点上跟一个复选框。点击用户、用户组和角色树上的节点对相应权限主体进行授权</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">授权信息存入</span>
				<span lang="EN-US">
						<font face="Times New Roman">ACL</font>
				</span>
				<span style="font-family: 宋体;">表中</span>
				<font face="Times New Roman">
				</font>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">资源</span>
				<span lang="EN-US">
						<font face="Times New Roman">TYPE</font>
				</span>
				<span style="font-family: 宋体;">为</span>
				<span lang="EN-US">
						<font face="Times New Roman"> method</font>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt; text-indent: -18pt;">
				<span style="" lang="EN-US">
						<span style="">
								<font face="Times New Roman">3、<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"><font size="3">  </font></span></font>
						</span>
				</span>
				<span style="font-family: 宋体;">行级数据权限授权</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">已在上面做了说明即数据范围限定</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt; text-indent: -18pt;">
				<span style="" lang="EN-US">
						<span style="">
								<font face="Times New Roman">4、<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"><font size="3">  </font></span></font>
						</span>
				</span>
				<span style="font-family: 宋体;">大集中模式下的权限授权</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">其实所谓大集中模式控制的也不过是数据范围，考虑是所有相关表全部增加</span>
				<span lang="EN-US">
						<font face="Times New Roman">groupId</font>
				</span>
				<span style="font-family: 宋体;">字段，新增时添入该字段，读出时进行判断</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span lang="EN-US">
						<font face="Times New Roman">web</font>
				</span>
				<span style="font-family: 宋体;">页面：</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">“组织和用户管理”模块中，每个组织中都允许设定一个管理员，一旦设定管理员，该组织就进入大集中模式，即所有该组织的数据与其他同级组织互相隔离，仅上级组织可见。同时说明一点的是：该管理员与系统总的管理员权限一样，不同的是数据范围仅限制与该组织内部。</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">综述：</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">实际的授权部分采用了</span>
				<span lang="EN-US">
						<font face="Times New Roman">ACL</font>
				</span>
				<span style="font-family: 宋体;">，所以授权比较简单和直观</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
				<span style="font-family: 宋体;">系统资源和数据库操作资源分开两个表存储，这样可能会给用户带来不便，也就是授权时还需要切换，但这种不便似乎不好解决，因为一个是粗粒度的一个是细粒度的。</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt; text-indent: -18pt;">
				<img alt="Image00001.bmp" src="http://www.blogjava.net/images/blogjava_net/ronghao/Image00001.bmp" border="0" height="303" width="494" />
		</p>
<img src ="http://www.blogjava.net/RongHao/aggbug/56998.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/RongHao/" target="_blank">ronghao</a> 2006-07-06 17:47 <a href="http://www.blogjava.net/RongHao/archive/2006/07/06/56998.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>乱弹权限系统续一</title><link>http://www.blogjava.net/RongHao/archive/2006/07/03/56258.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Mon, 03 Jul 2006 02:50:00 GMT</pubDate><guid>http://www.blogjava.net/RongHao/archive/2006/07/03/56258.html</guid><wfw:comment>http://www.blogjava.net/RongHao/comments/56258.html</wfw:comment><comments>http://www.blogjava.net/RongHao/archive/2006/07/03/56258.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.blogjava.net/RongHao/comments/commentRss/56258.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/RongHao/services/trackbacks/56258.html</trackback:ping><description><![CDATA[问题的提出：我们的需求是什么？<br />首先是系统中需要哪些权限。<br />权限应该分类四类：   <br />  一是系统方面，主要是对模块的权限划分 ，具体就是可见不可见，用户能不能对该模块进行再授权  <br />  二是数据库操作权限，主要是浏览、增加，修改，删除记录，也可以理解为对象权限   <br />  三是行级数据权限，又可以叫做对象实例级权限，主要是考虑到不是每个用户都可以看到所有记录的，比如在工资管理中一个部门用户就只能看到本部门人员的工资，甚至只能看到本部门什么职位以下的人员的工资。<br />  四是列级数据权限，即数据字段的权限，不是每个用户都可以看到或是修改所有的字段的。<br />具体四类可能的权限划分如下：<br />  一系统权限，可见/可再授权   <br />  二数据库操作权限，浏览/增加/修改/删除   <br />  三行级数据权限，数据范围<br />  四列级数据权限，可见/修改<br />然后是可能存在的权限模式，现在考虑的是大集中模式下的权限管理<br />  理解：什么是大集中模式下的权限管理。举个例子总公司下面有分公司A和分公司B，总公司系统管理员分别在分公司A和分公司B中设定分公司系统管理员，则分公司A和分公司B数据是互不可见的，分公司系统管理员只对各自分公司负责，他们可以同时建立一个相同名字的角色，但这两个角色是不同的。即下级只可以看到自己，上级可以看到所有。这个管理是可以嵌套的，即分公司A下面可能还会存在分公司，分公司下面还会有新的分部门。。。。<img src ="http://www.blogjava.net/RongHao/aggbug/56258.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/RongHao/" target="_blank">ronghao</a> 2006-07-03 10:50 <a href="http://www.blogjava.net/RongHao/archive/2006/07/03/56258.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>也来乱弹权限系统</title><link>http://www.blogjava.net/RongHao/archive/2006/06/29/55773.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Thu, 29 Jun 2006 08:29:00 GMT</pubDate><guid>http://www.blogjava.net/RongHao/archive/2006/06/29/55773.html</guid><wfw:comment>http://www.blogjava.net/RongHao/comments/55773.html</wfw:comment><comments>http://www.blogjava.net/RongHao/archive/2006/06/29/55773.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/RongHao/comments/commentRss/55773.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/RongHao/services/trackbacks/55773.html</trackback:ping><description><![CDATA[最近在设计权限方面的内容，有些想法，乱弹一下。个人觉得实现权限系统主要是三个方面：<br />1、授权。主要是授权模型的维护，如资源、角色、用户、部门的对应关系等。<br />2、认证。主要是用户身份的认证，以及取出用户的权限。<br />3、校验权限。当用户对某一资源进行操作时，将用户的权限与操作该资源所应有的权限进行比对校验。<br />在对这三个方面进行说明前，也想说说对数据权限的看法。什么是数据权限，很简单，<br />考虑一种场景 （javaeye里的例子）<br />看看销售数据 <br />A销售员可以看到自己的销售情况和每一笔具体销售业务，但是看不到B的 <br />B销售员可以看到自己的销售情况和每一笔具体销售业务，但是看不到A的 <br />分公司销售经理则可以看到本部门的A和B的销售情况，但是看不到其他分公司的销售业务 <br />集团销售Boss可以看到集团内所有分公司的销售业务数据 <br />共同点：他们都可以看到“销售数据”这一模块<br />不同点：他们读取数据的范围是不一样的<br />这个也可以叫做实例级权限控制。有人认为这种权限一般是放在业务里做的, 如果非要用一个固定的模型实现,可以参考 ACL, 不过也是要在业务里写 ACL 相关代码的。确实，以前自己也都是放在业务里做的，但一直认为这也应该是权限系统的一部分，通过用户的权限来构造不同的sql语句。具体通过AOP实现，好象已经有个开源的东西还没看（lllyq的<a href="http://bba96.dev.java.net">http://bba96.dev.java.net</a>）。ACL对实例级权限控制感觉效率会有问题，个人看法。<br />具体来说：<br />1、授权<br />   具体开发里简便的授权方式已经成了用户必提的要求，很明显，仅仅基于role和权限交互是远远不够的。现实中你必须把角色、用户、部门三者全部与权限挂钩。而这三者毫无疑问地就会存在权限继承的问题。考虑一下，在部门A增加一个用户，很显然该用户会继承部门A的权限；同时如果在部门A下增加一个部门角色，该角色应不应该也继承部门A的权限呢？也许需要一个规则接口，具体规则实现看客户需求。<br />   再说说资源，这里仅讨论系统资源不考虑数据资源。考虑一个“业务管理”的模块，该模块下面还有“项目管理”，“物品管理”，“采购管理”三个模块，当对用户赋予了“业务管理”模块的查看权限，用户是否同时对“项目管理”，“物品管理”，“采购管理”具有查看权限呢？这里同样存在资源权限继承的问题。客户的需求是不同的，所以同样需要一个资源权限继承的规则接口。<br />   最后说说授权信息的保存。考虑ACL。表设计：资源ID，权限主体ID，权限主体TYPE，资源操作权限。一开始考虑权限主体ID就是UserID，这样会在认证的时候效率很高，但考虑到部门A下有100个用户，当对部门A增加一个权限时，实际上会往ACL表里插入100条记录，这就让人不能接受了。<br />2、认证<br />   其实就两个方面，一是检查是否存在这个用户，二是取出用户的权限。呵呵，这里有些绝对了，取出用户的权限完全可以放到校验权限里来做，不必这里一次性全读出来。用户的权限放在一个List里，对象可以构造一个，两个属性：资源ID和资源操作权限。取出用户的权限时候要用到上面定义的规则接口来组装用户实际的所有权限。<br />2、校验权限<br />   这个就比较简单了，个人倾向于在Action里完成这个工作，需要进行权限检查的Action实现一个接口，接口里有一个 public boolean hasPermission() ，写个拦截器拦截即可。这里的关键还是通过资源权限继承的规则接口来校验用户操作该资源的权限。<br />完全是个人乱弹，欢迎拍砖：）<img src ="http://www.blogjava.net/RongHao/aggbug/55773.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/RongHao/" target="_blank">ronghao</a> 2006-06-29 16:29 <a href="http://www.blogjava.net/RongHao/archive/2006/06/29/55773.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>