﻿<?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-szhswl-文章分类-ACEGI</title><link>http://www.blogjava.net/szhswl/category/28241.html</link><description>宋针还的个人空间</description><language>zh-cn</language><lastBuildDate>Fri, 21 Dec 2007 17:02:27 GMT</lastBuildDate><pubDate>Fri, 21 Dec 2007 17:02:27 GMT</pubDate><ttl>60</ttl><item><title>基于角色的权限控制(RBAC)</title><link>http://www.blogjava.net/szhswl/articles/169283.html</link><dc:creator>宋针还</dc:creator><author>宋针还</author><pubDate>Fri, 21 Dec 2007 04:54:00 GMT</pubDate><guid>http://www.blogjava.net/szhswl/articles/169283.html</guid><wfw:comment>http://www.blogjava.net/szhswl/comments/169283.html</wfw:comment><comments>http://www.blogjava.net/szhswl/articles/169283.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/szhswl/comments/commentRss/169283.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/szhswl/services/trackbacks/169283.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;相信side对Acegi的扩展会给你耳目一新的感觉,提供完整的扩展功能,管理界面,中文注释和靠近企业的安全策略。side只对Acegi不符合企业应用需要的功能进行扩展,尽量不改动其余部分来实现全套权限管理功能,以求能更好地适应Acegi升级。
<p>&nbsp;</p>
<h2>3.1 基于角色的权限控制(RBAC)</h2>
<p>&nbsp;&nbsp;&nbsp; Acegi 自带的 sample 表设计很简单: users表{username,password,enabled} authorities表{username,authority},这样简单的设计无法适应复杂的权限需求,故SpringSide选用RBAC模型对权限控制数据库表进行扩展。&nbsp;RBAC引入了ROLE的概念,使User(用户)和Permission(权限)分离,一个用户拥有多个角色,一个角色拥有有多个相应的权限,从而减少了权限管理的复杂度,可更灵活地支持安全策略。 </p>
<p><img src="http://www.springside.org.cn/docs/reference/images/acegi/RBAC.jpg"  alt="" /></p>
<p>&nbsp;&nbsp;&nbsp; 同时,我们也引入了resource(资源)的概念,一个资源对应多个权限，资源分为ACL,URL,和FUNTION三种。注意，URL和FUNTION的权限命名需要以AUTH_开头才会有资格参加投票, 同样的ACL权限命名需要ACL_开头。</p>
<br />
<h2>3.2&nbsp;管理和使用EhCache</h2>
<h3>3.2.1 设立缓存</h3>
<p>在SpringSide里的 Acegi 扩展使用 <a href="http://ehcache.sourceforge.net/">EhCache</a><span style="font-family: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">&nbsp;就作为一种缓存解决方案,以缓存用户和资源的信息和相对应的权限信息。</span></p>
<p><span style="font-family: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">首先需要一个在classpath的<span style="font-family: Arial"> <span lang="EN-US">ehcache.xml </span></span><span style="font-family: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">文件，用于配置</span><span style="font-family: Arial"> <span lang="EN-US">EhCache。</span></span></span></p>
<pre><span style="font-family: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial"><span style="font-family: Arial"><span lang="EN-US">&lt;ehcache&gt;<br />
</span></span></span><span style="font-family: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial"><span style="font-family: Arial"><span lang="EN-US">&nbsp;&nbsp;&nbsp;</span></span></span><span style="font-family: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial"><span style="font-family: Arial"><span lang="EN-US">&nbsp;&nbsp;&nbsp; &lt;defaultCache<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; maxElementsInMemory="10000"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; eternal="false"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; overflowToDisk="true"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timeToIdleSeconds="0"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timeToLiveSeconds="0"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; diskPersistent="false"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;diskExpiryThreadIntervalSeconds= "120"/&gt; <br />
&nbsp;&nbsp;&nbsp; &lt;!-- acegi cache--&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;cache name="<font color="#000080">userCache</font>"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; maxElementsInMemory="10000"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; eternal="true"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;overflowToDisk= "true"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;!-- acegi cache--&gt;   <br />
&nbsp;&nbsp;&nbsp; &lt;cache name="<font color="#000080">resourceCache</font>"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; maxElementsInMemory="10000"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; eternal="true"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; overflowToDisk="true"/&gt;<br />
&lt;/ehcache&gt;</span></span></span></pre>
<p><span lang="EN-US" style="font-family: Arial">&nbsp;&nbsp;&nbsp;&nbsp; maxElementsInMemory设定了允许在Cache中存放的数据数目，eternal设定Cache是否会过期，overflowToDisk设定内存不足的时候缓存到硬盘，timeToIdleSeconds和timeToLiveSeconds设定缓存游离时间和生存时间，diskExpiryThreadIntervalSeconds设定缓存在硬盘上的生存时间，注意当eternal="true"时，timeToIdleSeconds，timeToLiveSeconds和diskExpiryThreadIntervalSeconds都是无效的。</span></p>
<p><span lang="EN-US" style="font-family: Arial">&lt;defaultCache&gt;是除制定的Cache外其余所有Cache的设置，针对Acegi 的情况, 专门设置了userCache和resourceCache，都设为永不过期。在applicationContext-acegi-security.xml中相应的调用是</span></p>
<pre><span lang="EN-US" style="font-family: Arial">&lt;bean id="userCacheBackend" class="org.springframework.cache.ehcache.EhCacheFactoryBean"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="cacheManager" ref="cacheManager"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="<font color="#000080">cacheName</font>" value="<font color="#000080">  userCache</font>"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/bean&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;bean id="userCache" class="org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache" autowire="byName"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="cache" ref="userCacheBackend"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/bean&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;bean id="resourceCacheBackend" class="org.springframework.cache.ehcache.EhCacheFactoryBean"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="cacheManager" ref="cacheManager"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="<font color="#000080">cacheName</font>" value="<font color="#000080">  resourceCache</font>"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/bean&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;bean id="resourceCache" class="org.springside.modules.security.service.acegi.cache.ResourceCache" autowire="byName"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="cache" ref="resourceCacheBackend"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/bean&gt;<br />
&lt;bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/&gt;<br />
</pre>
</span>
<p><span lang="EN-US" style="font-family: Arial">"cacheName" 就是设定在<span lang="EN-US">ehcache.xml </span>中相应Cache的名称。</span></p>
<p><span lang="EN-US" style="font-family: Arial">userCache使用的是Acegi 的EhCacheBasedUserCache(实现了UserCache接口), resourceCache是SpringSide的扩展类</span></p>
<pre><span lang="EN-US" style="font-family: Arial">public interface <font color="#000080">UserCache</font>   {</span><span lang="EN-US" style="font-family: Arial"><br />
&nbsp;&nbsp;&nbsp; public UserDetails <font color="#800080">getUserFromCache</font>   (String username);</span><span lang="EN-US" style="font-family: Arial"><br />
&nbsp;&nbsp;&nbsp; public void <font color="#800080">putUserInCache</font>   (UserDetails user);</span><span lang="EN-US" style="font-family: Arial"><br />
&nbsp;&nbsp;&nbsp; public void <font color="#800080">removeUserFromCache</font>   (String username);<br />
}</span></pre>
<pre><span lang="EN-US" style="font-family: Arial">public class <font color="#000080">ResourceCache</font>   {<br />
</span><span lang="EN-US" style="font-family: Arial">&nbsp;&nbsp;&nbsp; public ResourceDetails <font color="#800080">getAuthorityFromCache</font>   (String resString) {...</span><span lang="EN-US" style="font-family: Arial">&nbsp;&nbsp; }<br />
</span><span lang="EN-US" style="font-family: Arial">&nbsp;&nbsp;&nbsp; public void <font color="#800080">putAuthorityInCache</font>   (ResourceDetails resourceDetails) {...&nbsp; }<br />
&nbsp;</span><span lang="EN-US" style="font-family: Arial">&nbsp;&nbsp; public void <font color="#800080">removeAuthorityFromCache</font>   (String resString) {... }<br />
</span><span lang="EN-US" style="font-family: Arial">&nbsp;&nbsp;&nbsp; public List getUrlResStrings() {... }<br />
</span><span lang="EN-US" style="font-family: Arial">&nbsp;&nbsp;&nbsp; public List getFunctions() {.. }</span><span lang="EN-US" style="font-family: Arial"><br />
}</span></pre>
<p><span lang="EN-US" style="font-family: Arial">UserCache 就是通过EhCache对UserDetails 进行缓存管理, 而ResourceCache 是对ResourceDetails 类进行缓存管理</span></p>
<pre><span lang="EN-US" style="font-family: Arial">public interface <font color="#000080">UserDetails</font>   extends Serializable {<br />
</span><span lang="EN-US" style="font-family: Arial">&nbsp;&nbsp;&nbsp; public boolean isAccountNonExpired();</span><span lang="EN-US" style="font-family: Arial"><br />
&nbsp;&nbsp;&nbsp; public boolean isAccountNonLocked();</span><span lang="EN-US" style="font-family: Arial"><br />
&nbsp;&nbsp;&nbsp; public GrantedAuthority[] <font color="#800080">getAuthorities</font>();</span><span lang="EN-US" style="font-family: Arial"><br />
&nbsp;&nbsp;&nbsp; public boolean isCredentialsNonExpired();</span><span lang="EN-US" style="font-family: Arial"><br />
&nbsp;&nbsp;&nbsp; public boolean isEnabled();</span><span lang="EN-US" style="font-family: Arial"><br />
&nbsp;&nbsp;&nbsp; public String getPassword();</span><span lang="EN-US" style="font-family: Arial"><br />
&nbsp;&nbsp;&nbsp; public String getUsername();<br />
}</span></pre>
<pre><span lang="EN-US" style="font-family: Arial">public interface <font color="#000080">ResourceDetails</font>   extends Serializable {</span><span lang="EN-US" style="font-family: Arial"><br />
&nbsp;&nbsp;&nbsp; public String getResString();</span><span lang="EN-US" style="font-family: Arial"><br />
&nbsp;&nbsp;&nbsp; public String getResType();</span><span lang="EN-US" style="font-family: Arial"><br />
&nbsp;&nbsp;&nbsp; public GrantedAuthority[] <font color="#800080">getAuthorities</font>();<br />
</span><span lang="EN-US" style="font-family: Arial">}</span></pre>
<p><span lang="EN-US" style="font-family: Arial">UserDetails 包含用户信息和相应的权限，ResourceDetails 包含资源信息和相应的权限。</span></p>
<pre><span lang="EN-US" style="font-family: Arial">public interface <font color="#000080">GrantedAuthority</font>     {<br />
&nbsp;&nbsp;&nbsp; public String <font color="#800080">getAuthority</font>   ();<br />
}</span></pre>
<p><span lang="EN-US" style="font-family: Arial"><font face="Tahoma">&nbsp;&nbsp;&nbsp;&nbsp; </font>GrantedAuthority 就是权限信息，在Acegi 的 sample 里<span lang="EN-US" style="font-family: Arial">GrantedAuthority 的信息如</span>ROLE_USER, ROLE_SUPERVISOR, ACL_CONTACT_DELETE, ACL_CONTACT_ADMIN等等，网上也有很多例子把角色作为<span lang="EN-US" style="font-family: Arial">GrantedAuthority ，但事实上看看ACL 就知道， Acegi本身根本就没有角色这个概念，<span lang="EN-US" style="font-family: Arial">GrantedAuthority 包含的信息应该是权限，对于非ACL的权限用 AUTH_ 开头更为合理, 如SpringSide里的 AUTH_ADMIN_LOGIN, AUTH_BOOK_MANAGE 等等。</span></span> </span></p>
<h3>3.2.2 管理缓存</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 使用AcegiCacheManager对<span lang="EN-US" style="font-family: Arial">userCache和resourceCache进行统一缓存管理。<font face="Tahoma">当在后台对用户信息进行修改或赋权的时候, 在更新数据库同时就会调用acegiCacheManager相应方法, 从数据库中读取数据并替换cache中相应部分,使cache与数据库同步。</font></p>
</span>
<pre><span lang="EN-US" style="font-family: Arial">public class AcegiCacheManager extends BaseService {<br />
</span><span lang="EN-US" style="font-family: Arial">&nbsp;&nbsp;&nbsp; private ResourceCache <font color="#800080">resourceCache</font>   ;<br />
</span><span lang="EN-US" style="font-family: Arial">&nbsp;&nbsp;&nbsp; private UserCache <font color="#800080">userCache</font>   ;</span><span lang="EN-US" style="font-family: Arial"><br />
<font color="#800000">&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * 修改User时更改userCache  <br />
&nbsp;&nbsp;&nbsp;&nbsp; */</font> <br />
&nbsp;&nbsp;&nbsp; public void <font color="#800080">modifyUserInCache</font>   (User user, String orgUsername) {...&nbsp;&nbsp;&nbsp; }<br />
<font color="#800000">&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * 修改Resource时更改resourceCache  <br />
&nbsp;&nbsp;&nbsp;&nbsp; */</font> <br />
&nbsp;&nbsp;&nbsp; public void <font color="#800080">modifyResourceInCache</font>   (Resource resource, String orgResourcename) {...&nbsp;&nbsp;&nbsp; }<br />
<font color="#800000">&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; *   修改权限时同时修改userCache和resourceCache<br />
&nbsp;&nbsp;&nbsp;&nbsp; */</font> <br />
&nbsp;&nbsp;&nbsp; public void <font color="#800080">modifyPermiInCache</font>   (Permission permi, String orgPerminame) {...&nbsp; }<br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * <font color="#800000">User授予角色时更改userCache</font>  <br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public void <font color="#800080">authRoleInCache</font>   (User user) {...&nbsp;&nbsp;&nbsp; }<br />
<font color="#800000">&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Role授予权限时更改userCache和resourceCache  <br />
&nbsp;&nbsp;&nbsp;&nbsp; */</font> <br />
&nbsp;&nbsp;&nbsp; public void <font color="#800080">authPermissionInCache</font>   (Role role) {...&nbsp; }<br />
&nbsp;<font color="#800000">&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * Permissioni授予资源时更改resourceCache  <br />
&nbsp;&nbsp;&nbsp;&nbsp; */</font> <br />
&nbsp;&nbsp;&nbsp; public void <font color="#800080">authResourceInCache</font>   (Permission permi) {...&nbsp; }<br />
<font color="#800000">&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; *   初始化userCache<br />
&nbsp;&nbsp;&nbsp;&nbsp; */</font> <br />
&nbsp;&nbsp;&nbsp; public void <font color="#800080">initUserCache</font>   () {...&nbsp; }<br />
<font color="#800000">&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; *   初始化resourceCache<br />
&nbsp;&nbsp;&nbsp;&nbsp; */</font> <br />
&nbsp;&nbsp;&nbsp; public void <font color="#800080">initResourceCache</font>   () {... }<br />
<font color="#800000">&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; *  获取所有的url资源<br />
&nbsp;&nbsp;&nbsp;&nbsp; */</font> <br />
&nbsp;&nbsp;&nbsp; public List <font color="#800080">getUrlResStrings</font>   () {... &nbsp;}<br />
<font color="#800000">&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * 获取所有的Funtion资源  <br />
&nbsp;&nbsp;&nbsp;&nbsp; */</font> <br />
&nbsp;&nbsp;&nbsp; public List <font color="#800080">getFunctions</font>   () {...&nbsp; }<br />
<font color="#800000">&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp;&nbsp; * 根据资源串获取资源  <br />
&nbsp;&nbsp;&nbsp;&nbsp; */</font> <br />
&nbsp;&nbsp;&nbsp; public ResourceDetails <font color="#800080">getAuthorityFromCache</font>   (String resString) {...&nbsp; }<br />
&nbsp;&nbsp;<br />
&nbsp;......<br />
<br />
<br />
}</span></pre>
<p>&nbsp;</p>
<h2>3.3 资源权限定义扩展</h2>
<p><span lang="EN-US" style="font-family: Arial"><font face="Tahoma">&nbsp;&nbsp;&nbsp;&nbsp; </font></span>Acegi给出的sample里,资源权限对照关系是配置在xml中的,试想一下如果你的企业安全应用有500个用户,100个角色权限的时候,维护这个xml将是个繁重无比的工作,如何动态更改用户权限更是个头痛的问题。</p>
<pre>&nbsp;&nbsp; &lt;bean id="contactManagerSecurity" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="authenticationManager"&gt;&lt;ref bean="authenticationManager"/&gt;&lt;/property&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="accessDecisionManager"&gt;&lt;ref local="businessAccessDecisionManager"/&gt;&lt;/property&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="afterInvocationManager"&gt;&lt;ref local="afterInvocationManager"/&gt;&lt;/property&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="objectDefinitionSource"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;value&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sample.contact.ContactManager.create=ROLE_USER<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sample.contact.ContactManager.getAllRecipients=ROLE_USER<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sample.contact.ContactManager.getAll=ROLE_USER,AFTER_ACL_COLLECTION_READ<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sample.contact.ContactManager.getById=ROLE_USER,AFTER_ACL_READ<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sample.contact.ContactManager.delete=ACL_CONTACT_DELETE<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sample.contact.ContactManager.deletePermission=ACL_CONTACT_ADMIN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sample.contact.ContactManager.addPermission=ACL_CONTACT_ADMIN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/value&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />
&nbsp;&nbsp; &lt;/bean&gt;</pre>
<pre>&nbsp;&nbsp;&lt;bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="authenticationManager"&gt;&lt;ref bean="authenticationManager"/&gt;&lt;/property&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="accessDecisionManager"&gt;&lt;ref local="httpRequestAccessDecisionManager"/&gt;&lt;/property&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="objectDefinitionSource"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;value&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PATTERN_TYPE_APACHE_ANT<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /index.jsp=ROLE_ANONYMOUS,ROLE_USER<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /hello.htm=ROLE_ANONYMOUS,ROLE_USER<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /logoff.jsp=ROLE_ANONYMOUS,ROLE_USER<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /switchuser.jsp=ROLE_SUPERVISOR<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /j_acegi_switch_user=ROLE_SUPERVISOR<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /acegilogin.jsp*=ROLE_ANONYMOUS,ROLE_USER<br />
&nbsp;&nbsp;&nbsp;&nbsp;   /**=ROLE_USER<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/value&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />
&nbsp;&nbsp; &lt;/bean&gt;</pre>
<p>&nbsp;对如此不Pragmatic的做法,SpringSide进行了扩展, 让Acegi 能动态读取数据库中的权限资源关系。</p>
<h3>3.3.1 Aop Invocation Authorization</h3>
<pre>&nbsp;&nbsp;&nbsp; &lt;bean id="methodSecurityInterceptor" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="authenticationManager" ref="authenticationManager"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="objectDefinitionSource" ref="methodDefinitionSource"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/bean&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;bean id="methodDefinitionSource" class="org.springside.security.service.acegi.DBMethodDefinitionSource"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="acegiCacheManager" ref="acegiCacheManager"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/bean&gt;</pre>
<p><span lang="EN-US" style="font-family: Arial"><font face="Tahoma">&nbsp;&nbsp;&nbsp;&nbsp; </font></span>研究下Aceig的源码,<strong>ObjectDefinitionSource</strong>的实际作用是返回一个<strong>ConfigAttributeDefinition</strong>对象，而Acegi Sample 的方式是用<strong>MethodDefinitionSourceEditor</strong>把xml中的文本Function资源权限对应关系信息加载到<strong>MethodDefinitionMap </strong>( MethodDefinitionSource&nbsp;的实现类 )中, 再组成ConfigAttributeDefinition，而我们的扩展目标是从缓存中读取信息来组成ConfigAttributeDefinition。</p>
<p><span lang="EN-US" style="font-family: Arial"><font face="Tahoma">&nbsp;&nbsp;&nbsp;&nbsp; </font></span><strong>MethodSecurityInterceptor</strong>是通过调用AbstractMethodDefinitionSource的<strong>lookupAttributes(method)</strong>方法获取ConfigAttributeDefinition。所以我们需要实现自己的O<span lang="EN-US" style="font-family: Arial"><font face="Tahoma">bjectDefinitionSource，</font></span>继承<strong>AbstractMethodDefinitionSource</strong>并实现其lookupAttributes方法,从缓存中读取资源权限对应关系组成并返回ConfigAttributeDefinition即可。SpringSide中的<strong>DBMethodDefinitionSource</strong>类的部分实现如下 :</p>
<pre>public class DBMethodDefinitionSource <font color="#000080">extends</font> <font color="#000080">AbstractMethodDefinitionSource</font> {<br />
......<br />
&nbsp;&nbsp;&nbsp; protected <font color="#008080">ConfigAttributeDefinition</font> <font color="#800080">lookupAttributes</font>(Method mi) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Assert.notNull(mi, "lookupAttrubutes in the DBMethodDefinitionSource is null");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String methodString = mi.getDeclaringClass().getName() + "." + mi.getName();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!acegiCacheManager.isCacheInitialized()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#800000">//初始化Cache<br />
</font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; acegiCacheManager.initResourceCache();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#800000">//获取所有的function<br />
</font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List methodStrings = acegiCacheManager.getFunctions();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set auths = new HashSet();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#800000">//取权限的合集</font><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (Iterator iter = methodStrings.iterator(); iter.hasNext();) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String mappedName = (String) iter.next();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (methodString.equals(mappedName)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; || <font color="#800080">isMatch</font>(methodString, mappedName)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ResourceDetails resourceDetails = acegiCacheManager.getAuthorityFromCache(mappedName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (resourceDetails == null) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GrantedAuthority[] authorities = resourceDetails.getAuthorities();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (authorities == null || authorities.length == 0) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; auths.addAll(Arrays.asList(authorities));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (auths.size() == 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ConfigAttributeEditor configAttrEditor = new ConfigAttributeEditor();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String authoritiesStr = " ";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (Iterator iter = auths.iterator(); iter.hasNext();) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GrantedAuthority authority = (GrantedAuthority) iter.next();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; authoritiesStr += authority.getAuthority() + ",";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String authStr = authoritiesStr.substring(0, authoritiesStr.length() - 1);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; configAttrEditor.setAsText(authStr);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#800000">//组装并返回ConfigAttributeDefinition</font><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (ConfigAttributeDefinition) configAttrEditor.getValue();<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; ......<br />
}</pre>
<p>要注意几点的是: <br />
1) 初始化Cache是比较浪费资源的，所以SpringSide中除第一次访问外的Cache的更新是针对性更新。</p>
<p>2) 因为method采用了匹配方式(详见 isMatch() 方法) , 即对于*Book和save*这两个资源来说，只要当前访问方法是Book结尾或以save开头都算匹配得上，所以应该取这些能匹配上的资源的相对应的权限的合集。</p>
<p>3) 使用ConfigAttributeEditor 能更方便地组装ConfigAttributeDefinition。 </p>
<h3>3.3.2 Filter Invocation Authorization</h3>
<pre>&nbsp;&nbsp;&nbsp; &lt;bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="authenticationManager" ref="authenticationManager"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="objectDefinitionSource" ref="filterDefinitionSource"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/bean&gt;<br />
<br />
&nbsp;&nbsp;&nbsp; &lt;bean id="filterDefinitionSource" class="org.springside.security.service.acegi.DBFilterInvocationDefinitionSource"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="convertUrlToLowercaseBeforeComparison" value="true"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="useAntPath" value="true"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="acegiCacheManager" ref="acegiCacheManager"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/bean&gt;</pre>
<p><span lang="EN-US" style="font-family: Arial"><font face="Tahoma">&nbsp;&nbsp;&nbsp;&nbsp; </font></span>PathBasedFilterInvocationDefinitionMap和RegExpBasedFilterInvocationDefinitionMap都是 <strong>FilterInvocationDefinitionSource</strong>的实现类,当PATTERN_TYPE_APACHE_ANT字符串匹配上时时,<strong>FilterInvocationDefinitionSourceEditor </strong>选用PathBasedFilterInvocationDefinitionMap 把xml中的文本URL资源权限对应关系信息加载。</p>
<p><span lang="EN-US" style="font-family: Arial"><font face="Tahoma">&nbsp;&nbsp;&nbsp;&nbsp; </font></span><strong>FilterSecurityInterceptor</strong>通过FilterInvocationDefinitionSource的<strong>lookupAttributes(url)</strong>方法获取ConfigAttributeDefinition。 所以，我们可以通过继承FilterInvocationDefinitionSource的抽象类<strong>AbstractFilterInvocationDefinitionSource</strong>，并实现其lookupAttributes方法,从缓存中读取URL资源权限对应关系即可。SpringSide的<strong>DBFilterInvocationDefinitionSource</strong>类部分实现如下:</p>
<pre>public class DBFilterInvocationDefinitionSource <font color="#000080">extends&nbsp;AbstractFilterInvocationDefinitionSource</font> {<br />
<br />
......<br />
&nbsp;&nbsp;&nbsp; public ConfigAttributeDefinition lookupAttributes(String url) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!acegiCacheManager.isCacheInitialized()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; acegiCacheManager.initResourceCache();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (isUseAntPath()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Strip anything after a question mark symbol, as per SEC-161.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int firstQuestionMarkIndex = url.lastIndexOf("?");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (firstQuestionMarkIndex != -1) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; url = url.substring(0, firstQuestionMarkIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List urls = acegiCacheManager.getUrlResStrings();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#800000">//URL资源倒叙排序</font><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Collections.sort(urls);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Collections.reverse(urls);<br />
<font color="#800000">//是否先全部转为小写再比较</font><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (convertUrlToLowercaseBeforeComparison) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; url = url.toLowerCase();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GrantedAuthority[] authorities = new GrantedAuthority[0];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (Iterator iterator = urls.iterator(); iterator.hasNext();) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String resString = (String) iterator.next();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; boolean matched = false;<br />
<font color="#800000">              //可选择使用AntPath和Perl5两种不同匹配模式  </font> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (isUseAntPath()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; matched = pathMatcher.match(resString, url);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Pattern compiledPattern;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Perl5Compiler compiler = new Perl5Compiler();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; compiledPattern = compiler.compile(resString,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Perl5Compiler.READ_ONLY_MASK);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (MalformedPatternException mpe) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new IllegalArgumentException(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "Malformed regular expression: " + resString);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; matched = matcher.matches(url, compiledPattern);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (matched) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ResourceDetails rd = acegiCacheManager.getAuthorityFromCache(resString);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; authorities = rd.getAuthorities();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (authorities.length &gt; 0) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String authoritiesStr = " ";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; authorities.length; i++) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; authoritiesStr += authorities[i].getAuthority() + ",";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String authStr = authoritiesStr.substring(0, authoritiesStr<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .length() - 1);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ConfigAttributeEditor configAttrEditor = new ConfigAttributeEditor();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; configAttrEditor.setAsText(authStr);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (ConfigAttributeDefinition) configAttrEditor.getValue();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
......<br />
&nbsp;}</pre>
<p>继承<font color="#000000">AbstractFilterInvocationDefinitionSource</font>注意几点：<br />
1)&nbsp; 需要先把获取回来的URL资源按倒序派序，以达到 a/b/c/d.* 在 a/.* 之前的效果(详见 Acegi sample 的applicationContext-acegi-security.xml 中的filterInvocationInterceptor的注释)，为的是更具体的URL可以先匹配上，而获取具体URL的权限，如a/b/c/d.*权限AUTH_a, AUTH_b 才可查看,&nbsp; a/.* 需要权限AUTH_a 才可查看，则如果当前用户只拥有权限AUTH_b,则他只可以查看a/b/c/d.jsp 而不能察看a/d.jsp。</p>
<p>2)&nbsp;基于上面的原因，故第一次匹配上的就是当前所需权限，而不是取权限的合集。</p>
<p>3) 可以选用AntPath 或 Perl5 的资源匹配方式，感觉AntPath匹配方式基本足够。</p>
<p>4) Filter 权限控制比较适合于较粗颗粒度的权限，如设定某个模块下的页面是否能访问等，对于具体某个操作如增删修改，是否能执行，用Method&nbsp;&nbsp;Invocation 会更佳些，所以注意两个方面一起控制效果更好</p>
<p>&nbsp;</p>
<h2>3.4 授权操作</h2>
<p><span lang="EN-US" style="font-family: Arial"><font face="Tahoma">&nbsp;&nbsp;&nbsp;&nbsp; </font></span>RBAC模型中有不少多对多的关系，这些关系都能以一个中间表的形式来存放，而Hibernate中可以不建这中间表对应的hbm.xml , 以资源与权限的配置为例，如下:</p>
<pre>&lt;hibernate-mapping package="org.springside.modules.security.domain"&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;class name="Permission" table="PERMISSIONS" dynamic-insert="true" dynamic-update="true"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;cache usage="nonstrict-read-write"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;id name="id" column="ID"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;generator class="native"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/id&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="name" column="NAME" not-null="true"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="descn" column="DESCN"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="operation" column="OPERATION"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="status" column="STATUS"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;set name="roles" table="ROLE_PERMIS" lazy="true" inverse="true" cascade="save-update" batch-size="5"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;key&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;column name="PERMIS_ID" not-null="true"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/key&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;many-to-many class="Role" column="ROLE_ID" outer-join="auto"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/set&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;set name="resources" table="PERMIS_RESC" lazy="true" inverse="false" cascade="save-update" batch-size="5"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;key&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;column name="PERMIS_ID" not-null="true"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/key&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;many-to-many class="Resource" column="RESC_ID"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/set&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/class&gt;<br />
&lt;/hibernate-mapping&gt;</pre>
<pre>&lt;hibernate-mapping package="org.springside.modules.security.domain"&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;class name="Resource" table="RESOURCES" dynamic-insert="true" dynamic-update="true"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;cache usage="nonstrict-read-write"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;id name="id" column="ID"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;generator class="native"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/id&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="name" column="NAME" not-null="true"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="resType" column="RES_TYPE" not-null="true"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="resString" column="RES_STRING" not-null="true"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="descn" column="DESCN"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;set name="permissions" table="PERMIS_RESC" lazy="true" inverse="true" cascade="save-update" batch-size="5"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;key&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;column name="RESC_ID" not-null="true"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/key&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;many-to-many class="Permission" column="PERMIS_ID" outer-join="auto"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/set&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/class&gt;<br />
&lt;/hibernate-mapping&gt;</pre>
<p>配置时注意几点:</p>
<p>1) 因为是分配某个权限的资源，所以权限是主控方，把inverse设为false，资源是被控方inverse设为true</p>
<p>2) cascade是"save-update"，千万别配成delete</p>
<p>3) 只需要 permission.getResources().add(resource)， permission.getResources()..remove(resource) 即可很方便地完成授权和取消授权操作</p>
<img src ="http://www.blogjava.net/szhswl/aggbug/169283.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/szhswl/" target="_blank">宋针还</a> 2007-12-21 12:54 <a href="http://www.blogjava.net/szhswl/articles/169283.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Acegi安全系统的配置</title><link>http://www.blogjava.net/szhswl/articles/169244.html</link><dc:creator>宋针还</dc:creator><author>宋针还</author><pubDate>Fri, 21 Dec 2007 02:58:00 GMT</pubDate><guid>http://www.blogjava.net/szhswl/articles/169244.html</guid><wfw:comment>http://www.blogjava.net/szhswl/comments/169244.html</wfw:comment><comments>http://www.blogjava.net/szhswl/articles/169244.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/szhswl/comments/commentRss/169244.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/szhswl/services/trackbacks/169244.html</trackback:ping><description><![CDATA[Acegi 的配置看起来非常复杂,但事实上在实际项目的安全应用中我们并不需要那么多功能,清楚的了解Acegi配置中各项的功能，有助于我们灵活的运用Acegi于实践中。
<h2>2.1 在Web.xml中的配置</h2>
<p>1)&nbsp; <strong>FilterToBeanProxy</strong><br />
　　Acegi通过实现了Filter接口的FilterToBeanProxy提供一种特殊的使用Servlet Filter的方式，它委托Spring中的Bean -- FilterChainProxy来完成过滤功能，这好处是简化了web.xml的配置，并且充分利用了Spring IOC的优势。FilterChainProxy包含了处理认证过程的filter列表，每个filter都有各自的功能。</p>
<pre>&nbsp; &nbsp; &lt;filter&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;filter-name&gt;Acegi Filter Chain Proxy&lt;/filter-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;filter-class&gt;org.acegisecurity.util.FilterToBeanProxy&lt;/filter-class&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;init-param&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-name&gt;targetClass&lt;/param-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-value&gt;org.acegisecurity.util.FilterChainProxy&lt;/param-value&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/init-param&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/filter&gt;</pre>
<p>2) <strong>filter-mapping</strong><br />
　　&lt;filter-mapping&gt;限定了FilterToBeanProxy的URL匹配模式,只有*.do和*.jsp和/j_acegi_security_check 的请求才会受到权限控制，对javascript,css等不限制。</p>
<pre>&nbsp;&nbsp; &lt;filter-mapping&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;filter-name&gt;Acegi Filter Chain Proxy&lt;/filter-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;url-pattern&gt;*.do&lt;/url-pattern&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/filter-mapping&gt;<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; &lt;filter-mapping&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;filter-name&gt;Acegi Filter Chain Proxy&lt;/filter-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;url-pattern&gt;*.jsp&lt;/url-pattern&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/filter-mapping&gt;<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; &lt;filter-mapping&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;filter-name&gt;Acegi Filter Chain Proxy&lt;/filter-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;url-pattern&gt;/j_acegi_security_check&lt;/url-pattern&gt;<br />
&lt;/filter-mapping&gt;</pre>
<p>3) <strong>HttpSessionEventPublisher</strong><br />
　　&lt;listener&gt;的HttpSessionEventPublisher用于发布HttpSessionApplicationEvents和HttpSessionDestroyedEvent事件给spring的applicationcontext。</p>
<pre>&nbsp;&nbsp;&nbsp; &lt;listener&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;listener-class&gt;org.acegisecurity.ui.session.HttpSessionEventPublisher&lt;/listener-class&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/listener&gt;<br />
</pre>
<h2><br />
2.2 在applicationContext-acegi-security.xml中</h2>
<h3>2.2.1 FILTER CHAIN</h3>
<p>　　FilterChainProxy会按顺序来调用这些filter,使这些filter能享用Spring ioc的功能, CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON定义了url比较前先转为小写， PATTERN_TYPE_APACHE_ANT定义了使用Apache ant的匹配模式 </p>
<pre>    &lt;bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="filterInvocationDefinitionSource"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;value&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PATTERN_TYPE_APACHE_ANT<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,<br />
basicProcessingFilter,rememberMeProcessingFilter,anonymousProcessingFilter,<br />
exceptionTranslationFilter,filterInvocationInterceptor<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/value&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/bean&gt;</pre>
<h3>2.2.2 基础认证</h3>
<p>1) <strong>authenticationManager</strong><br />
　　起到认证管理的作用，它将验证的功能委托给多个Provider，并通过遍历Providers, 以保证获取不同来源的身份认证，若某个Provider能成功确认当前用户的身份，authenticate()方法会返回一个完整的包含用户授权信息的Authentication对象，否则会抛出一个AuthenticationException。<br />
Acegi提供了不同的AuthenticationProvider的实现,如：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DaoAuthenticationProvider 从数据库中读取用户信息验证身份<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AnonymousAuthenticationProvider 匿名用户身份认证<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RememberMeAuthenticationProvider 已存cookie中的用户信息身份认证<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AuthByAdapterProvider 使用容器的适配器验证身份<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CasAuthenticationProvider 根据Yale中心认证服务验证身份, 用于实现单点登陆<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JaasAuthenticationProvider 从JASS登陆配置中获取用户信息验证身份<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RemoteAuthenticationProvider 根据远程服务验证用户身份<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RunAsImplAuthenticationProvider 对身份已被管理器替换的用户进行验证<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; X509AuthenticationProvider 从X509认证中获取用户信息验证身份<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TestingAuthenticationProvider 单元测试时使用</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 每个认证者会对自己指定的证明信息进行认证，如DaoAuthenticationProvider仅对UsernamePasswordAuthenticationToken这个证明信息进行认证。</p>
<pre>&lt;bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="providers"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;list&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;ref local="daoAuthenticationProvider"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;ref local="anonymousAuthenticationProvider"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;ref local="rememberMeAuthenticationProvider"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/list&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />
&lt;/bean&gt;</pre>
<p><br />
2) <strong>daoAuthenticationProvider</strong><br />
　　进行简单的基于数据库的身份验证。DaoAuthenticationProvider获取数据库中的账号密码并进行匹配，若成功则在通过用户身份的同时返回一个包含授权信息的Authentication对象，否则身份验证失败，抛出一个AuthenticatiionException。</p>
<pre>&nbsp;&nbsp;&nbsp; &lt;bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="userDetailsService" ref="jdbcDaoImpl"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="userCache" ref="userCache"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="passwordEncoder" ref="passwordEncoder"/&gt;<br />
&nbsp;&nbsp; &lt;/bean&gt;</pre>
<p><br />
3) <strong>passwordEncoder</strong> <br />
　　使用加密器对用户输入的明文进行加密。Acegi提供了三种加密器:<br />
PlaintextPasswordEncoder—默认，不加密，返回明文.<br />
ShaPasswordEncoder—哈希算法(SHA)加密<br />
Md5PasswordEncoder—消息摘要(MD5)加密</p>
<pre>&lt;bean id="passwordEncoder" class="org.acegisecurity.providers.encoding.Md5PasswordEncoder"/&gt;</pre>
<p><br />
4) <strong>jdbcDaoImpl</strong> <br />
　　用于在数据中获取用户信息。 acegi提供了用户及授权的表结构，但是您也可以自己来实现。通过usersByUsernameQuery这个SQL得到你的(用户ID,密码,状态信息);通过authoritiesByUsernameQuery这个SQL得到你的(用户ID,授权信息)</p>
<pre>
&lt;bean id="jdbcDaoImpl"
class="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;property name="dataSource"
ref="dataSource"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property
name="usersByUsernameQuery"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;value&gt;select loginid,passwd,1 from users where loginid =
?&lt;/value&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;/property&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property
name="authoritiesByUsernameQuery"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;value&gt;select u.loginid,p.name from users u,roles r,permissions
p,user_role ur,role_permis rp where u.id=ur.user_id and r.id=ur.role_id and
p.id=rp.permis_id
and<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
r.id=rp.role_id and p.status='1' and
u.loginid=?&lt;/value&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;/property&gt;<br />
&lt;/bean&gt;</pre>
<p>5) <strong>userCache　&amp;&nbsp; resourceCache</strong> <br />
　　缓存用户和资源相对应的权限信息。每当请求一个受保护资源时，daoAuthenticationProvider就会被调用以获取用户授权信息。如果每次都从数据库获取的话，那代价很高，对于不常改变的用户和资源信息来说，最好是把相关授权信息缓存起来。(详见 <a href="http://www.springside.org.cn/docs/reference/Acegi4.htm">2.6.3 资源权限定义扩展</a> )<br />
userCache提供了两种实现: NullUserCache和EhCacheBasedUserCache, NullUserCache实际上就是不进行任何缓存，EhCacheBasedUserCache是使用Ehcache来实现缓功能。</p>
<pre>&nbsp;&nbsp;&nbsp; &lt;bean id="userCacheBackend"
class="org.springframework.cache.ehcache.EhCacheFactoryBean"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;property name="cacheManager"
ref="cacheManager"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;property name="cacheName" value="userCache"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/bean&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;bean id="userCache"
class="org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache"
autowire="byName"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property
name="cache" ref="userCacheBackend"/&gt;<br />
&nbsp;&nbsp;&nbsp;
&lt;/bean&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;bean id="resourceCacheBackend"
class="org.springframework.cache.ehcache.EhCacheFactoryBean"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;property name="cacheManager"
ref="cacheManager"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;property name="cacheName" value="resourceCache"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/bean&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;bean id="resourceCache"
class="org.springside.modules.security.service.acegi.cache.ResourceCache"
autowire="byName"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property
name="cache" ref="resourceCacheBackend"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/bean&gt;</pre>
<p><br />
6) <strong>basicProcessingFilter</strong> <br />
　　用于处理HTTP头的认证信息，如从Spring远程协议(如Hessian和Burlap)或普通的浏览器如IE,Navigator的HTTP头中获取用户信息，将他们转交给通过authenticationManager属性装配的认证管理器。如果认证成功，会将一个Authentication对象放到会话中，否则，如果认证失败，会将控制转交给认证入口点(通过authenticationEntryPoint属性装配)</p>
<pre>&nbsp;&nbsp;&nbsp; &lt;bean id="basicProcessingFilter" class="org.acegisecurity.ui.basicauth.BasicProcessingFilter"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="authenticationManager" ref="authenticationManager"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="authenticationEntryPoint" ref="basicProcessingFilterEntryPoint"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/bean&gt;</pre>
<p>7) <strong>basicProcessingFilterEntryPoint</strong> <br />
　　通过向浏览器发送一个HTTP401(未授权)消息，提示用户登录。<br />
处理基于HTTP的授权过程， 在当验证过程出现异常后的"去向"，通常实现转向、在response里加入error信息等功能。</p>
<pre> &lt;bean
id="basicProcessingFilterEntryPoint"
class="org.acegisecurity.ui.basicauth.BasicProcessingFilterEntryPoint"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;property name="realmName" value="SpringSide Realm"/&gt;<br />
&lt;/bean&gt;</pre>
<p>8) <strong>authenticationProcessingFilterEntryPoint</strong> <br />
　　当抛出AccessDeniedException时，将用户重定向到登录界面。属性loginFormUrl配置了一个登录表单的URL,当需要用户登录时，authenticationProcessingFilterEntryPoint会将用户重定向到该URL</p>
<pre>
&lt;bean id="authenticationProcessingFilterEntryPoint"
class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;property
name="loginFormUrl"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;value&gt;/security/login.jsp&lt;/value&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;/property&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property
name="forceHttps" value="false"/&gt;<br />
&lt;/bean&gt;</pre>
<h2>2.2.3 HTTP安全请求</h2>
<p>1) <strong>httpSessionContextIntegrationFilter</strong><br />
　　每次request前 HttpSessionContextIntegrationFilter从Session中获取Authentication对象，在request完后, 又把Authentication对象保存到Session中供下次request使用,此filter必须其他Acegi filter前使用，使之能跨越多个请求。</p>
<pre>&lt;bean id="httpSessionContextIntegrationFilter" class="org.acegisecurity.context.HttpSessionContextIntegrationFilter"&gt;&lt;/bean&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;bean id="httpRequestAccessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="allowIfAllAbstainDecisions" value="false"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="decisionVoters"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;list&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;ref bean="roleVoter"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/list&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />
&lt;/bean&gt;</pre>
<p><br />
2) <strong>httpRequestAccessDecisionManager</strong><br />
　　经过投票机制来决定是否可以访问某一资源(URL或方法)。allowIfAllAbstainDecisions为false时如果有一个或以上的decisionVoters投票通过,则授权通过。可选的决策机制有ConsensusBased和UnanimousBased</p>
<pre>&nbsp;&nbsp;&nbsp; &lt;bean id="httpRequestAccessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="allowIfAllAbstainDecisions" value="false"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="decisionVoters"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;list&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;ref bean="roleVoter"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/list&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/bean&gt;</pre>
<p><br />
3) <strong>roleVoter</strong><br />
&nbsp;　　必须是以rolePrefix设定的value开头的权限才能进行投票,如AUTH_ , ROLE_</p>
<pre>&nbsp;&nbsp;&nbsp; &lt;bean id="roleVoter" class="org.acegisecurity.vote.RoleVoter"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="rolePrefix" value="AUTH_"/&gt;<br />
&nbsp;&nbsp; &lt;/bean&gt;</pre>
<p>4）<strong>exceptionTranslationFilter</strong><br />
　　异常转换过滤器，主要是处理AccessDeniedException和AuthenticationException，将给每个异常找到合适的"去向"&nbsp;</p>
<pre>&nbsp;&nbsp; &lt;bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="authenticationEntryPoint" ref="authenticationProcessingFilterEntryPoint"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/bean&gt;</pre>
<p>5) <strong>authenticationProcessingFilter</strong><br />
　　和servlet spec差不多,处理登陆请求.当身份验证成功时，AuthenticationProcessingFilter会在会话中放置一个Authentication对象，并且重定向到登录成功页面<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; authenticationFailureUrl定义登陆失败时转向的页面<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; defaultTargetUrl定义登陆成功时转向的页面<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; filterProcessesUrl定义登陆请求的页面<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rememberMeServices用于在验证成功后添加cookie信息</p>
<pre>&nbsp;&nbsp;&nbsp; &lt;bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="authenticationManager" ref="authenticationManager"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="authenticationFailureUrl"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;value&gt;/security/login.jsp?login_error=1&lt;/value&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="defaultTargetUrl"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;value&gt;/admin/index.jsp&lt;/value&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="filterProcessesUrl"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;value&gt;/j_acegi_security_check&lt;/value&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="rememberMeServices" ref="rememberMeServices"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/bean&gt;</pre>
<p>6) <strong>filterInvocationInterceptor</strong><br />
　　在执行转向url前检查objectDefinitionSource中设定的用户权限信息。首先，objectDefinitionSource中定义了访问URL需要的属性信息(这里的属性信息仅仅是标志，告诉accessDecisionManager要用哪些voter来投票)。然后，authenticationManager掉用自己的provider来对用户的认证信息进行校验。最后，有投票者根据用户持有认证和访问url需要的属性，调用自己的voter来投票，决定是否允许访问。</p>
<pre>&nbsp;&nbsp;&nbsp; &lt;bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="authenticationManager" ref="authenticationManager"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="objectDefinitionSource" ref="filterDefinitionSource"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/bean&gt;</pre>
<p><br />
7) <strong>filterDefinitionSource </strong>(详见 <a href="http://www.springside.org.cn/docs/reference/Acegi4.htm">2.6.3 资源权限定义扩展</a>)<br />
　　自定义DBFilterInvocationDefinitionSource从数据库和cache中读取保护资源及其需要的访问权限信息&nbsp;</p>
<pre>&lt;bean id="filterDefinitionSource" class="org.springside.modules.security.service.acegi.DBFilterInvocationDefinitionSource"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="convertUrlToLowercaseBeforeComparison" value="true"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="useAntPath" value="true"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="acegiCacheManager" ref="acegiCacheManager"/&gt;<br />
&lt;/bean&gt;</pre>
<h2>2.2.4 方法调用安全控制</h2>
<p>(详见 <a href="http://www.springside.org.cn/docs/reference/Acegi4.htm">2.6.3 资源权限定义扩展</a>)</p>
<p>1) methodSecurityInterceptor<br />
　　在执行方法前进行拦截，检查用户权限信息<br />
2) methodDefinitionSource<br />
　　自定义MethodDefinitionSource从cache中读取权限</p>
<pre>&nbsp;&nbsp; &lt;bean id="methodSecurityInterceptor" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="authenticationManager" ref="authenticationManager"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="objectDefinitionSource" ref="methodDefinitionSource"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/bean&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;bean id="methodDefinitionSource" class="org.springside.modules.security.service.acegi.DBMethodDefinitionSource"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="acegiCacheManager" ref="acegiCacheManager"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/bean&gt;</pre>
<img src ="http://www.blogjava.net/szhswl/aggbug/169244.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/szhswl/" target="_blank">宋针还</a> 2007-12-21 10:58 <a href="http://www.blogjava.net/szhswl/articles/169244.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Acegi简介</title><link>http://www.blogjava.net/szhswl/articles/169237.html</link><dc:creator>宋针还</dc:creator><author>宋针还</author><pubDate>Fri, 21 Dec 2007 02:25:00 GMT</pubDate><guid>http://www.blogjava.net/szhswl/articles/169237.html</guid><wfw:comment>http://www.blogjava.net/szhswl/comments/169237.html</wfw:comment><comments>http://www.blogjava.net/szhswl/articles/169237.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/szhswl/comments/commentRss/169237.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/szhswl/services/trackbacks/169237.html</trackback:ping><description><![CDATA[<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><a>&nbsp;&nbsp;&nbsp; Acegi安全系统，是一个用于Spring Framework的安全框架，能够和目前流行的Web容器无缝集成。它使用了Spring的方式提供了安全和认证安全服务，包括使用Bean Context，拦截器和面向接口的编程方式。因此，Acegi安全系统能够轻松地适用于复杂的安全需求。<br />
            &nbsp;&nbsp;&nbsp; Acegi安全系统，是一个用于Spring Framework的安全框架，能够和目前流行的Web容器无缝集成。它使用了Spring的方式提供了安全和认证安全服务，包括使用Bean Context，拦截器和面向接口的编程方式。因此，Acegi安全系统能够轻松地适用于复杂的安全需求。<br />
            &nbsp;&nbsp;&nbsp; 安全涉及到两个不同的概念，认证和授权。前者是关于确认用户是否确实是他们所宣称的身份。授权则是关于确认用户是否有允许执行一个特定的操作。<br />
            &nbsp;&nbsp;&nbsp; 在Acegi安全系统中，需要被认证的用户，系统或代理称为"Principal"。Acegi安全系统和其他的安全系统不同，它并没有角色和用户组的概念。<br />
            Acegi系统设计<br />
            关键组件<br />
            &nbsp;&nbsp;&nbsp; Acegi安全系统包含以下七个关键的功能组件：<br />
            &nbsp;&nbsp;&nbsp; 1 Authentication对象，包含了Principal，Credential和Principal的授权信息。同时还可以包含关于发起认证请求的客户的其他信息，如IP地址。<br />
            &nbsp;&nbsp;&nbsp; 2 ContextHolder对象，使用ThreadLocal储存Authentication对象的地方。<br />
            &nbsp;&nbsp;&nbsp; 3 AuthenticationManager，用于认证ContextHolder中的Authentication对象。<br />
            &nbsp;&nbsp;&nbsp; 4 AccessDecissionManager，用于授权一个特定的操作。<br />
            &nbsp;&nbsp;&nbsp; 5 RunAsManager，当执行特定的操作时，用于选择性地替换Authentication对象。<br />
            &nbsp;&nbsp;&nbsp; 6 Secure Object拦截器，用于协调AuthenticationManager，AccessDecissionManager，RunAsManager和特定操作的执行。<br />
            &nbsp;&nbsp;&nbsp; 7 ObjectDefinitionSource，包含了特定操作的授权定义。<br />
            &nbsp;&nbsp;&nbsp; 这七个关键的功能组件的关系如下图所示（图中灰色部分是关键组件）：<br />
            <br />
            <strong>安全管理对象</strong><br />
            &nbsp;&nbsp;&nbsp; Acegi安全系统目前支持两类安全管理对象。<br />
            &nbsp;&nbsp;&nbsp; 第一类的安全管理对象管理AOP Alliance的MethodInvocation，开发人员可以用它来保护Spring容器中的业务对象。为了使Spring管理的Bean可以作为 MethodInvocation来使用，Bean可以通过ProxyFactoryBean和BeanNameAutoProxyCreator来管理，就像在Spring的事务管理一样使用。<br />
            &nbsp;&nbsp;&nbsp; 第二类是FilterInvocation。它用过滤器（Filter）来创建，并简单地包装了HTTP的ServletRequest， ServletResponse和FilterChain。FilterInvocation可以用来保护HTTP资源。通常，开发人员并不需要了解它的工作机制，因为他们只需要将Filter加入web.xml，Acegi安全系统就可以工作了。<br />
            <br />
            <strong>安全配置参数</strong><br />
            &nbsp;&nbsp;&nbsp; 每个安全管理对象都可以描述数量不限的各种安全认证请求。例如，MethodInvocation对象可以描述带有任意参数的任意方法的调用，而FilterInvocation可以描述任意的HTTP URL。<br />
            &nbsp;&nbsp;&nbsp; Acegi安全系统需要记录应用于每个认证请求的安全配置参数。例如，对于BankManager.getBalance（int accountNumber）方法和BankManager.approveLoan（int applicationNumber）方法，它们需要的认证请求的安全配置很不相同。<br />
            &nbsp;&nbsp;&nbsp; 为了保存不同的认证请求的安全配置，需要使用配置参数。从实现的视角来看，配置参数使用ConfigAttribute接口来表示。Acegi安全系统提供了ConfigAttribute接口的一个实现，SecurityConfig，它把配置参数保存为一个字符串。<br />
            &nbsp;&nbsp;&nbsp; ConfigAttributeDefinition类是ConfigAttribute对象的一个简单的容器，它保存了和特定请求相关的ConfigAttribute的集合。<br />
            &nbsp;&nbsp;&nbsp; 当安全拦截器收到一个安全认证请求时，需要决定应用哪一个配置参数。换句话说，它需要找出应用于这个请求的 ConfigAttributeDefinition对象。这个查找的过程是由ObjectDefinitionSource接口来处理的。这个接口的主要方法是public ConfigAttributeDefinition getAttributes(Object object)，其中Object参数是一个安全管理对象。因为安全管理对象包含有认证请求的详细信息，所以 ObjectDefinitionSource接口的实现类可以从中获得所需的详细信息，以查找相关的ConfigAttributeDefiniton 对象。<br />
            <br />
            <br />
            <strong>Acegi如何工作</strong><br />
            &nbsp;&nbsp;&nbsp; 为了说明Acegi安全系统如何工作，我们设想一个使用Acegi的例子。通常，一个安全系统需要发挥作用，它必须完成以下的工作：<br />
            &nbsp;&nbsp;&nbsp; 1 首先，系统从客户端请求中获得Principal和Credential；<br />
            &nbsp;&nbsp;&nbsp; 2 然后系统认证Principal和Credential信息；<br />
            &nbsp;&nbsp;&nbsp; 3 如果认证通过，系统取出Principal的授权信息；<br />
            &nbsp;&nbsp;&nbsp; 4 接下来，客户端发起操作请求；<br />
            &nbsp;&nbsp;&nbsp; 5 系统根据预先配置的参数检查Principal对于该操作的授权；<br />
            &nbsp;&nbsp;&nbsp; 6 如果授权检查通过则执行操作，否则拒绝。<br />
            &nbsp;&nbsp;&nbsp; 那么，Acegi安全系统是如何完成这些工作的呢？首先，我们来看看Acegi安全系统的认证和授权的相关类： <br />
            &nbsp;&nbsp;&nbsp; 安全拦截器的抽象基类，它包含有两个管理类，AuthenticationManager和AccessDecisionManager。 AuthenticationManager用于认证ContextHolder中的Authentication对象（包含了Principal， Credential和Principal的授权信息）；AccessDecissionManager则用于授权一个特定的操作。<br />
            <br />
            &nbsp;&nbsp;&nbsp; 下面来看一个MethodSecurityInterceptor的例子：<br />
            </a>
            <pre class="overflow">    &lt;bean id="bankManagerSecurity" class="net.sf.acegisecurity.intercept.method.MethodSecurityInterceptor"&gt;<br />
            &lt;property name="validateConfigAttributes"&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;value&gt;true&lt;/value&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="authenticationManager"&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;ref bean="authenticationManager"/&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="accessDecisionManager"&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;ref bean="accessDecisionManager"/&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="objectDefinitionSource"&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;value&gt;net.sf.acegisecurity.context.BankManager.delete*=<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ROLE_SUPERVISOR,RUN_AS_SERVER<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; net.sf.acegisecurity.context.BankManager.getBalance=<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ROLE_TELLER,ROLE_SUPERVISOR,BANKSECURITY_CUSTOMER,RUN_<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/value&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />
            &nbsp;&nbsp; &lt;/bean&gt; </pre>
            <br />
            &nbsp;&nbsp;&nbsp; 上面的配置文件中，MethodSecurityInterceptor是AbstractSecurityInterceptor的一个实现类。它包含了两个管理器，authenticationManager和accessDecisionManager。这两者的配置如下：<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
            <pre class="overflow">&lt;bean id="authenticationDao" class="net.sf.acegisecurity.providers.dao.jdbc.JdbcDaoImpl"&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="dataSource"&gt;&lt;ref bean="dataSource"/&gt;&lt;/property&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/bean&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;bean id="daoAuthenticationProvider" <br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider"&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="authenticationDao"&gt;&lt;ref bean="authenticationDao"/&gt;&lt;/property&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/bean&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager"&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="providers"&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;list&gt;&lt;ref bean="daoAuthenticationProvider"/&gt;&lt;/list&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/bean&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;bean id="roleVoter" class="net.sf.acegisecurity.vote.RoleVoter"/&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;bean id="accessDecisionManager" class="net.sf.acegisecurity.vote.AffirmativeBased"&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="allowIfAllAbstainDecisions"&gt;&lt;value&gt;false&lt;/value&gt;&lt;/property&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="decisionVoters"&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;list&gt;&lt;ref bean="roleVoter"/&gt;&lt;/list&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/bean&gt;</pre>
            <br />
            <br />
            &nbsp;&nbsp;&nbsp; 准备工作做好了，现在我们来看看Acegi安全系统是如何实现认证和授权机制的。以使用HTTP BASIC认证的应用为例子，它包括下面的步骤：<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1. 用户登录系统，Acegi从acegisecurity.ui子系统的安全拦截器（如BasicProcessingFilter）中得到用户的登录信息（包括Principal和Credential）并放入Authentication对象，并保存在ContextHolder对象中；<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2. 安全拦截器将Authentication对象交给AuthenticationManager进行身份认证，如果认证通过，返回带有Principal 授权信息的Authentication对象。此时ContextHolder对象的Authentication对象已拥有Principal的详细信息；<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3. 用户登录成功后，继续进行业务操作；<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4. 安全拦截器（bankManagerSecurity）收到客户端操作请求后，将操作请求的数据包装成安全管理对象（FilterInvocation或MethodInvocation对象）；<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5. 然后，从配置文件（ObjectDefinitionSource）中读出相关的安全配置参数ConfigAttributeDefinition；<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6. 接着，安全拦截器取出ContextHolder中的Authentication对象，把它传递给AuthenticationManager进行身份认证，并用返回值更新ContextHolder的Authentication对象；<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7. 将Authentication对象，ConfigAttributeDefinition对象和安全管理对象（secure Object）交给AccessDecisionManager，检查Principal的操作授权；<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8. 如果授权检查通过则执行客户端请求的操作，否则拒绝；<br />
            <br />
            <strong>AccessDecisionVoter</strong><br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注意上节的accessDecisionManager是一个AffirmativeBased类，它对于用户授权的投票策略是，只要通过其中的一个授权投票检查，即可通过；它的allowIfAllAbstainDecisions属性值是false，意思是如果所有的授权投票是都是弃权，则通不过授权检查。<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Acegi安全系统包括了几个基于投票策略的AccessDecisionManager，上节的RoleVoter就是其中的一个投票策略实现，它是 AccessDecisionVoter的一个子类。AccessDecisionVoter的具体实现类通过投票来进行授权决策， AccessDecisionManager则根据投票结果来决定是通过授权检查，还是抛出AccessDeniedException例外。<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AccessDecisionVoter接口共有三个方法：<br />
            public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config);<br />
            public boolean supports(ConfigAttribute attribute);<br />
            public boolean supports(Class clazz);<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 其中的vote方法返回int返回值，它们是AccessDecisionVoter的三个静态成员属性：ACCESS_ABSTAIN,，ACCESS_DENIED和ACCESS_GRANTED，它们分别是弃权，否决和赞成。<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Acegi安全系统中，使用投票策略的AccessDecisionManager共有三个具体实现类：AffirmativeBased、 ConsensusBased和UnanimousBased。它们的投票策略是，AffirmativeBased类只需有一个投票赞成即可通过； ConsensusBased类需要大多数投票赞成即可通过；而UnanimousBased类需要所有的投票赞成才能通过。<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RoleVoter类是一个Acegi安全系统AccessDecisionVoter接口的实现。如果ConfigAttribute以ROLE_开头，RoleVoter则进行投票。如果GrantedAuthority的getAutority方法的String返回值匹配一个或多个以ROLE_ 开头的ConfigAttribute，则投票通过，否则不通过。如果没有以ROLE_开头的ConfigAttribute，RoleVoter则弃权。</td>
        </tr>
    </tbody>
</table>
<img src ="http://www.blogjava.net/szhswl/aggbug/169237.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/szhswl/" target="_blank">宋针还</a> 2007-12-21 10:25 <a href="http://www.blogjava.net/szhswl/articles/169237.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Acegi 参考的部分翻译</title><link>http://www.blogjava.net/szhswl/articles/169215.html</link><dc:creator>宋针还</dc:creator><author>宋针还</author><pubDate>Fri, 21 Dec 2007 01:20:00 GMT</pubDate><guid>http://www.blogjava.net/szhswl/articles/169215.html</guid><wfw:comment>http://www.blogjava.net/szhswl/comments/169215.html</wfw:comment><comments>http://www.blogjava.net/szhswl/articles/169215.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/szhswl/comments/commentRss/169215.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/szhswl/services/trackbacks/169215.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 本文档是"Spring框架下Acegi安全系统"(Acegi Security System for Spring)的一份参考指南，Acegi安全系统是由一序列类构成,这些类为Spring框架提供认证和授权服务。我得感谢这份参考在Spring框架中用DocBook配置进行了精心的包装。Spring小组在他们的DocBook中对Chris Bauer (Hibernate)的帮助表示感谢。第...&nbsp;&nbsp;<a href='http://www.blogjava.net/szhswl/articles/169215.html'>阅读全文</a><img src ="http://www.blogjava.net/szhswl/aggbug/169215.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/szhswl/" target="_blank">宋针还</a> 2007-12-21 09:20 <a href="http://www.blogjava.net/szhswl/articles/169215.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>acegi-security-sample-contacts-filter例子学习(二)</title><link>http://www.blogjava.net/szhswl/articles/168839.html</link><dc:creator>宋针还</dc:creator><author>宋针还</author><pubDate>Wed, 19 Dec 2007 11:56:00 GMT</pubDate><guid>http://www.blogjava.net/szhswl/articles/168839.html</guid><wfw:comment>http://www.blogjava.net/szhswl/comments/168839.html</wfw:comment><comments>http://www.blogjava.net/szhswl/articles/168839.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/szhswl/comments/commentRss/168839.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/szhswl/services/trackbacks/168839.html</trackback:ping><description><![CDATA[<p>功能实现分析</p>
<p>这个例子使用了HSQL做数据库，spring的AOP作为基础，使用Acegi做安全控制组件。<br />
联系人管理的web应用在启动时候，会做一系列初始化动作：<br />
1. 读取web.xml文件，</p>
<p>2. 并解析文件里的内容。<br />
a) context-param元素。<br />
i. contextConfigLocation属性。这个属性定义了spring所需要的3个属性文件。它们分别是：applicationContext -acegi-security.xml、applicationContext-common-business.xml、 applicationContext-common-authorization.xml<br />
ii. log4jConfigLocation属性。这个属性定义了log4j配置文件。</p>
<p>b) filter元素。<br />
这里定义了acegi的一个过滤器。Acegi的大部分过滤器都是这样配置的。使用FilterToBeanProxy组件，给它传递一个targetClass属性。这个targetClass必须实现javax.servlet.Filter接口。<br />
这里配置的是FilterChainProxy。这个FilterChainProxy比较好用，可以为它定义一串filter属性。这些filter将会按照定义的顺序被调用。例如，<br />
&lt;bean id="filterChainProxy" class="net.sf.acegisecurity.util.FilterChainProxy"&gt;<br />
&lt;property name="filterInvocationDefinitionSource"&gt;<br />
&lt;value&gt;<br />
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON<br />
PATTERN_TYPE_APACHE_ANT<br />
/**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,basicProcessingFilter,rememberMeProcessingFilter,anonymousProcessingFilter,securityEnforcementFilter<br />
&lt;/value&gt;<br />
&lt;/property&gt;<br />
&lt;/bean&gt;<br />
这个过滤器的mapping是&#8220;/*&#8221;。<br />
c) listener元素。<br />
i. ContextLoaderListener。这个是Spring使用来加载根applicationcontext。并分别解析 applicationContext-acegi-security.xml、applicationContext-common- business.xml、applicationContext-common-authorization.xml等配置文件，把相关的对象初始化<br />
iii. Log4jConfigListener。这个是spring用来初始化log4j组件的listener。<br />
iv. HttpSessionEventPublisher。这个组件将发布HttpSessionCreatedEvent和HttpSessionDestroyedEvent事件给spring的applicationcontext。<br />
d) servlet元素。<br />
i. contacts。这里采用了spring的MVC框架， 所以这个servlet是spring MVC的一个核心控制器（org.springframework.web.servlet.DispatcherServlet）。这个servlet 启动时候，会从contacts-servlet.xml里面读取信息，并做相关的初始化。<br />
v. remoting。也是spring MVC的一个核心控制器。与contacts不同，这个servlet主要是提供web services服务。这个servlet启动时候， 会从remoting-servlet.xml里面读取信息，并做相关的初始化。<br />
e) taglib元素。这里定义了spring的标f) 签库。<br />
3. 解析applicationContext-acegi-security.xml。<br />
a) 过滤器链。定义了一个FilterChainProxy，b) 并指c) 定了一系列的过滤器链。httpSessionContextIntegrationFilter, authenticationProcessingFilter,basicProcessingFilter,rememberMeProcessingFilter,anonymousProcessingFilter,securityEnforcementFilter<br />
d) 认证管理器。这个管理器由acegi提供。这个管理器需要一个providers参数。这个providers参数包含了提供系统认证的对象。<br />
i. daoAuthenticationProvider。一般用户认证。<br />
ii. anonymousAuthenticationProvider。匿名用户认证。<br />
iv. rememberMeAuthenticationProvider。记住我认证。</p>
<p>e) 密码加密。这里定义了一个acegi的Md5算法加密对象Md5PasswordEncoder。<br />
f) 定义了一个jdbcDao实现类。这个类由acegi提供的net.sf.acegisecurity.providers.dao.jdbc.JdbcDaoImpl。这个对象需要一个dataSource的参数。<br />
g) 定义daoAuthenticationProvider。这个对象由acegi提供。它有3个属性：<br />
authenticationDao。这里指向前面定义的jdbcDao。<br />
userCache。这里指向后面定义的user缓存对象。<br />
passwordEncoder。这里指向前面定义的密码加密对象。<br />
h) 用户缓存管理。<br />
为了缓存user，这里使用spring的ehcache来缓存user。缓存机制：<br />
i. 定义缓存管理器――CacheManager。这个对象是spring的EhCacheManagerFactoryBean对象<br />
ii. 定义user缓存实际执行对象――UserCacheBackend。这个对象是spring的EhCacheFactoryBean。它有两个属性：<br />
1. cacheManager。这里指向前面定义的缓存管理器。<br />
2. cacheName。<br />
iii. 定义user缓存――UserCache。它是acegi提供的EhCacheBasedUserCache对象。它有一个属性：<br />
1. cache。这里指向的是前面定义的userCacheBackend。</p>
<p>i) 定义接收来自DaoAuthenticationProvider的认证事件的listener――LoggerListener。<br />
j) <br />
4. 解析applicationContext-common-business.xml。<br />
a) dataSource.<br />
这里使用了spring的DriverManagerDataSource对象。这个对象是一个JDBC数据源的定义。<br />
b) TransactionManager。这里使用spring的DataSourceTransactionManager对象。<br />
c) 事务拦截器。这里使用spring的事务拦截器TransactionInterceptor。它有2个属性：<br />
transactionManager。这个属性指向前面定义的TransactionManager。<br />
transactionAttributeSource。这个属性里， 指定了ContactManager的各个方法的事务方面的要求。<br />
d) DataSourcePopulator。<br />
使用sample.contact.DataSourcePopulator对象，往HSQL里创建相关的表结构和数据。<br />
实现原理：DataSourcePopulator 实现了接口 InitializingBean。其中afterPropertiesSet方法将在spring初始化DataSourcePopulator后被调用。<br />
e) ContactDao。这里指向一个ContactDaoSpring对象。它继承spring的 JdbcDaoSupport，g) 并实现ContactDao接口。它是真正实现JDBC操作的对象。<br />
h) ContactManager。这里使用的是spring的ProxyFactoryBean。它有2个属性：<br />
i. ProxyInterfaces。代理接口：sample.contact.ContactManager</p>
<p>ii. InterceptorNames。拦截器名称。可以有多个，iv. 这里包括：transactionInterceptor、contactManagerSecurity、contactManagerTarget。其中，v. transactionInterceptor是前面定义的事务拦截器。ContactManagerSecurity则是在 applicationContext-common-authorization.xml里定义的方法调用授权。<br />
i) ContactManagerTarget。这里指向的是sample.contact.ContactManagerBackend对象。 ContactManagerBackend实现了ContactManager接口和InitializingBean接口。它有2个自定义属性： contactDao和basicAclExtendedDao。这里会调用ACL的API去做些创建权限和删除权限的工作。</p>
<img src ="http://www.blogjava.net/szhswl/aggbug/168839.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/szhswl/" target="_blank">宋针还</a> 2007-12-19 19:56 <a href="http://www.blogjava.net/szhswl/articles/168839.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>acegi-security-sample-contacts-filter例子学习(一)</title><link>http://www.blogjava.net/szhswl/articles/168837.html</link><dc:creator>宋针还</dc:creator><author>宋针还</author><pubDate>Wed, 19 Dec 2007 11:43:00 GMT</pubDate><guid>http://www.blogjava.net/szhswl/articles/168837.html</guid><wfw:comment>http://www.blogjava.net/szhswl/comments/168837.html</wfw:comment><comments>http://www.blogjava.net/szhswl/articles/168837.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/szhswl/comments/commentRss/168837.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/szhswl/services/trackbacks/168837.html</trackback:ping><description><![CDATA[<p><span style="font-size: 10.5pt; font-family: 宋体">这是一个</span><span lang="EN-US" style="font-size: 10.5pt" times="" new="" roman="">Acegi</span><span style="font-size: 10.5pt; font-family: 宋体">官方的例子。它以联系人的管理为例子，说明如何使用</span><span lang="EN-US" style="font-size: 10.5pt" times="" new="" roman="">Acegi</span><span style="font-size: 10.5pt; font-family: 宋体">作权限控制。这个例子包含在</span><span lang="EN-US" style="font-size: 10.5pt" times="" new="" roman="">acegi</span><span style="font-size: 10.5pt; font-family: 宋体">的包里面。下载地址：</span><span lang="EN-US" style="font-size: 10.5pt" times="" new="" roman=""><a href="http://prdownloads.sourceforge.net/acegisecurity/acegi-security-0.8.3.zip?download">http://prdownloads.sourceforge.net/acegisecurity/acegi-security-0.8.3.zip?download</a>。</span><br />
</p>
<p><font face="宋体">联系人管理说明了下列中心的<span lang="EN-US">Acegi安全控制能力: </span></font></p>
<ul>
    <li><strong><span lang="EN-US">Role-based security</span></strong><strong><span style="font-family: 宋体">（基于角色的安全）</span></strong><span style="font-family: 宋体">――每个责任人都是某个角色的一员。而角色被用来限制对某些安全对象的访问。</span><span lang="EN-US"> </span>
    <li><strong><span lang="EN-US">Domain object instance security</span></strong><strong><span style="font-family: 宋体">（域对象实例安全）</span></strong><span style="font-family: 宋体">――合同，这个系统里的主要域对象，拥有一个访问控制列表（</span><span lang="EN-US">ACL</span><span style="font-family: 宋体">），用来指明谁允许读、管理和删除对象。</span><span lang="EN-US"> </span>
    <li><strong><span lang="EN-US">Method invocation security</span></strong><strong><span style="font-family: 宋体">（方法调用安全）――</span></strong><span style="font-family: 宋体">这个</span> <code><span lang="EN-US" style="font-size: 10pt; font-family: 黑体">ContactManager</span></code><span style="font-family: 宋体">服务层对象</span> <span style="font-family: 宋体">包含一些受保护的和公开的方法。</span><span lang="EN-US"> </span>
    <li><strong><span lang="EN-US">Web request security</span></strong><strong><span style="font-family: 宋体">（</span><span lang="EN-US">Web</span></strong><strong><span style="font-family: 宋体">请求安全）</span></strong><span style="font-family: 宋体">――这个&#8220;</span><code><span lang="EN-US" style="font-size: 10pt; font-family: 黑体">/secure</span></code><span style="font-family: 宋体">&#8221;</span><span lang="EN-US">URI</span><span style="font-family: 宋体">路径被使用</span><span lang="EN-US">Acegi</span><span style="font-family: 宋体">安全保护，使得没有</span><code><span lang="EN-US" style="font-size: 10pt; font-family: 黑体">ROLE_USER</span></code><span lang="EN-US"> </span><span style="font-family: 宋体">角色的用户无法访问。</span><span lang="EN-US">. </span>
    <li><strong><span lang="EN-US">Security unaware application objects</span></strong><strong><span style="font-family: 宋体">（保护未知的应用对象）</span></strong><span style="font-family: 宋体">――受保护的对象与</span><span lang="EN-US">Acegi</span><span style="font-family: 宋体">之间没有明显的耦合或契约，所以它们没有察觉到安全是由</span><span lang="EN-US">Acegi </span><span style="font-family: 宋体">提供的。</span><span lang="EN-US">* </span>
    <li><strong><span lang="EN-US">Security taglib usage</span></strong><strong><span style="font-family: 宋体">（安全标签库使用）</span></strong><span style="font-family: 宋体">――所有的</span><span lang="EN-US">JSP</span><span style="font-family: 宋体">使用</span><span lang="EN-US">Acegi </span><span style="font-family: 宋体">安全标签库来封装安全信息。</span><span lang="EN-US">* </span>
    <li><strong><span lang="EN-US">Fully declarative security(</span></strong><strong><span style="font-family: 宋体">完全声明式的安全</span><span lang="EN-US">)</span></strong><span style="font-family: 宋体">――每一个安全方面特性都是在</span><span lang="EN-US">application context</span><span style="font-family: 宋体">里面使用标准的</span><span lang="EN-US">Acegi</span><span style="font-family: 宋体">安全对象来配置的。</span><span lang="EN-US"> * </span>
    <li><strong><span lang="EN-US">Database-sourced security data</span></strong><strong><span style="font-family: 宋体">（支持数据库来源的安全数据）</span></strong><span style="font-family: 宋体">――所有的用户、角色和</span><span lang="EN-US">ACL</span><span style="font-family: 宋体">信息都可以从一个兼容</span><span lang="EN-US">JDBC</span><span style="font-family: 宋体">的内存数据库获得。</span><span lang="EN-US"> </span>
    <li><strong><span lang="EN-US">Integrated form-based and BASIC authentication</span></strong><strong><span style="font-family: 宋体">（集成基于表单和</span><span lang="EN-US">BASIC</span></strong><strong><span style="font-family: 宋体">验证）――</span></strong> <span style="font-family: 宋体">任何</span><span lang="EN-US">BASIC</span><span style="font-family: 宋体">验证头部被检测以及作为验证使用。默认使用基于表单的普通交互式验证。</span><span lang="EN-US"> </span>
    <li><strong><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'">Remember-me services</span><span style="font-size: 10.5pt; font-family: 宋体">（记住我的服务）――</span></strong><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'"> Acegi</span><span style="font-size: 10.5pt; font-family: 宋体">安全的插件式的&#8220;</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'">remember-me</span><span style="font-size: 10.5pt; font-family: 宋体">&#8221;</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'"> </span><span style="font-size: 10.5pt; font-family: 宋体">策略被演示。在登录表单里有一个相关的选择框与之对应。</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'"> </span></li>
</ul>
<p>&nbsp;</p>
<span style="font-size: 10.5pt; font-family: 'Times New Roman'">
<p><span style="font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;联系人管理的业务功能描述：</span></p>
<p style="text-indent: -21pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span><font size="2">1. </font></span></span><span style="font-family: 宋体">每个用户登录后，可以看到一个联系人列表。例如，</span></p>
<h1><span lang="EN-US" style="font-size: 12pt"><font face="宋体">marissa's Contacts</font></span></h1>
<table cellpadding="0" border="0">
    <tbody>
        <tr>
            <td style="border-right: rgb(212,208,200); padding-right: 2.25pt; border-top: rgb(212,208,200); padding-left: 2.25pt; padding-bottom: 2.25pt; border-left: rgb(212,208,200); padding-top: 2.25pt; border-bottom: rgb(212,208,200); background-color: transparent">
            <p><strong><span lang="EN-US">id</span></strong></p>
            </td>
            <td style="border-right: rgb(212,208,200); padding-right: 2.25pt; border-top: rgb(212,208,200); padding-left: 2.25pt; padding-bottom: 2.25pt; border-left: rgb(212,208,200); padding-top: 2.25pt; border-bottom: rgb(212,208,200); background-color: transparent">
            <p><strong><span lang="EN-US">Name</span></strong></p>
            </td>
            <td style="border-right: rgb(212,208,200); padding-right: 2.25pt; border-top: rgb(212,208,200); padding-left: 2.25pt; padding-bottom: 2.25pt; border-left: rgb(212,208,200); padding-top: 2.25pt; border-bottom: rgb(212,208,200); background-color: transparent">
            <p><strong><span lang="EN-US">Email</span></strong></p>
            </td>
        </tr>
        <tr>
            <td style="border-right: rgb(212,208,200); padding-right: 2.25pt; border-top: rgb(212,208,200); padding-left: 2.25pt; padding-bottom: 2.25pt; border-left: rgb(212,208,200); padding-top: 2.25pt; border-bottom: rgb(212,208,200); background-color: transparent">
            <p><span lang="EN-US">1 </span></p>
            </td>
            <td style="border-right: rgb(212,208,200); padding-right: 2.25pt; border-top: rgb(212,208,200); padding-left: 2.25pt; padding-bottom: 2.25pt; border-left: rgb(212,208,200); padding-top: 2.25pt; border-bottom: rgb(212,208,200); background-color: transparent">
            <p><span lang="EN-US">John Smith </span></p>
            </td>
            <td style="border-right: rgb(212,208,200); padding-right: 2.25pt; border-top: rgb(212,208,200); padding-left: 2.25pt; padding-bottom: 2.25pt; border-left: rgb(212,208,200); padding-top: 2.25pt; border-bottom: rgb(212,208,200); background-color: transparent">
            <p><span lang="EN-US">john@somewhere.com </span></p>
            </td>
            <td style="border-right: rgb(212,208,200); padding-right: 2.25pt; border-top: rgb(212,208,200); padding-left: 2.25pt; padding-bottom: 2.25pt; border-left: rgb(212,208,200); padding-top: 2.25pt; border-bottom: rgb(212,208,200); background-color: transparent">
            <p><span lang="EN-US"><a href="http://localhost:8080/acegi-security-sample-contacts-filter/secure/del.htm?contactId=1">Del</a></span></p>
            </td>
            <td style="border-right: rgb(212,208,200); padding-right: 2.25pt; border-top: rgb(212,208,200); padding-left: 2.25pt; padding-bottom: 2.25pt; border-left: rgb(212,208,200); padding-top: 2.25pt; border-bottom: rgb(212,208,200); background-color: transparent">
            <p><span lang="EN-US"><a href="http://localhost:8080/acegi-security-sample-contacts-filter/secure/adminPermission.htm?contactId=1">Admin Permission</a></span></p>
            </td>
        </tr>
        <tr>
            <td style="border-right: rgb(212,208,200); padding-right: 2.25pt; border-top: rgb(212,208,200); padding-left: 2.25pt; padding-bottom: 2.25pt; border-left: rgb(212,208,200); padding-top: 2.25pt; border-bottom: rgb(212,208,200); background-color: transparent">
            <p><span lang="EN-US">2 </span></p>
            </td>
            <td style="border-right: rgb(212,208,200); padding-right: 2.25pt; border-top: rgb(212,208,200); padding-left: 2.25pt; padding-bottom: 2.25pt; border-left: rgb(212,208,200); padding-top: 2.25pt; border-bottom: rgb(212,208,200); background-color: transparent">
            <p><span lang="EN-US">Michael Citizen </span></p>
            </td>
            <td style="border-right: rgb(212,208,200); padding-right: 2.25pt; border-top: rgb(212,208,200); padding-left: 2.25pt; padding-bottom: 2.25pt; border-left: rgb(212,208,200); padding-top: 2.25pt; border-bottom: rgb(212,208,200); background-color: transparent">
            <p><span lang="EN-US">michael@xyz.com </span></p>
            </td>
            <td style="border-right: rgb(212,208,200); padding-right: 2.25pt; border-top: rgb(212,208,200); padding-left: 2.25pt; padding-bottom: 2.25pt; border-left: rgb(212,208,200); padding-top: 2.25pt; border-bottom: rgb(212,208,200); background-color: transparent">
            <p>&nbsp;</p>
            <br />
            </td>
            <td style="border-right: rgb(212,208,200); padding-right: 2.25pt; border-top: rgb(212,208,200); padding-left: 2.25pt; padding-bottom: 2.25pt; border-left: rgb(212,208,200); padding-top: 2.25pt; border-bottom: rgb(212,208,200); background-color: transparent">
            <p>&nbsp;</p>
            <br />
            </td>
        </tr>
        <tr>
            <td style="border-right: rgb(212,208,200); padding-right: 2.25pt; border-top: rgb(212,208,200); padding-left: 2.25pt; padding-bottom: 2.25pt; border-left: rgb(212,208,200); padding-top: 2.25pt; border-bottom: rgb(212,208,200); background-color: transparent">
            <p><span lang="EN-US">3 </span></p>
            </td>
            <td style="border-right: rgb(212,208,200); padding-right: 2.25pt; border-top: rgb(212,208,200); padding-left: 2.25pt; padding-bottom: 2.25pt; border-left: rgb(212,208,200); padding-top: 2.25pt; border-bottom: rgb(212,208,200); background-color: transparent">
            <p><span lang="EN-US">Joe Bloggs </span></p>
            </td>
            <td style="border-right: rgb(212,208,200); padding-right: 2.25pt; border-top: rgb(212,208,200); padding-left: 2.25pt; padding-bottom: 2.25pt; border-left: rgb(212,208,200); padding-top: 2.25pt; border-bottom: rgb(212,208,200); background-color: transparent">
            <p><span lang="EN-US">joe@demo.com </span></p>
            </td>
            <td style="border-right: rgb(212,208,200); padding-right: 2.25pt; border-top: rgb(212,208,200); padding-left: 2.25pt; padding-bottom: 2.25pt; border-left: rgb(212,208,200); padding-top: 2.25pt; border-bottom: rgb(212,208,200); background-color: transparent">
            <p><span lang="EN-US"><a href="http://localhost:8080/acegi-security-sample-contacts-filter/secure/del.htm?contactId=3">Del</a></span></p>
            </td>
            <td style="border-right: rgb(212,208,200); padding-right: 2.25pt; border-top: rgb(212,208,200); padding-left: 2.25pt; padding-bottom: 2.25pt; border-left: rgb(212,208,200); padding-top: 2.25pt; border-bottom: rgb(212,208,200); background-color: transparent">
            <p>&nbsp;</p>
            <br />
            </td>
        </tr>
        <tr>
            <td style="border-right: rgb(212,208,200); padding-right: 2.25pt; border-top: rgb(212,208,200); padding-left: 2.25pt; padding-bottom: 2.25pt; border-left: rgb(212,208,200); padding-top: 2.25pt; border-bottom: rgb(212,208,200); background-color: transparent">
            <p><span lang="EN-US">4 </span></p>
            </td>
            <td style="border-right: rgb(212,208,200); padding-right: 2.25pt; border-top: rgb(212,208,200); padding-left: 2.25pt; padding-bottom: 2.25pt; border-left: rgb(212,208,200); padding-top: 2.25pt; border-bottom: rgb(212,208,200); background-color: transparent">
            <p><span lang="EN-US">Karen Sutherland </span></p>
            </td>
            <td style="border-right: rgb(212,208,200); padding-right: 2.25pt; border-top: rgb(212,208,200); padding-left: 2.25pt; padding-bottom: 2.25pt; border-left: rgb(212,208,200); padding-top: 2.25pt; border-bottom: rgb(212,208,200); background-color: transparent">
            <p><span lang="EN-US">karen@sutherland.com </span></p>
            </td>
            <td style="border-right: rgb(212,208,200); padding-right: 2.25pt; border-top: rgb(212,208,200); padding-left: 2.25pt; padding-bottom: 2.25pt; border-left: rgb(212,208,200); padding-top: 2.25pt; border-bottom: rgb(212,208,200); background-color: transparent">
            <p><span lang="EN-US"><a href="http://localhost:8080/acegi-security-sample-contacts-filter/secure/del.htm?contactId=4">Del</a></span></p>
            </td>
            <td style="border-right: rgb(212,208,200); padding-right: 2.25pt; border-top: rgb(212,208,200); padding-left: 2.25pt; padding-bottom: 2.25pt; border-left: rgb(212,208,200); padding-top: 2.25pt; border-bottom: rgb(212,208,200); background-color: transparent">
            <p><span lang="EN-US"><a href="http://localhost:8080/acegi-security-sample-contacts-filter/secure/adminPermission.htm?contactId=4">Admin Permission</a></span></p>
            </td>
        </tr>
    </tbody>
</table>
<p><span lang="EN-US"><a href="http://localhost:8080/acegi-security-sample-contacts-filter/secure/add.htm"><font face="宋体" size="3">Add</font></a><font face="宋体" size="3"> </font></span></p>
<p><span style="font-family: 宋体">说明：用户没有权限访问的联系人信息，将不会显示。</span></p>
<p style="text-indent: -21pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span> <font size="2">2.</font> </span></span><span style="font-family: 宋体">用户可以增加新的联系人信息。</span></p>
<p style="text-indent: -21pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span> <font size="2">3.</font> </span></span><span style="font-family: 宋体">如果有删除权限，用户可以看到在联系人后面有一个&#8220;</span><span lang="EN-US">Del</span><span style="font-family: 宋体">&#8221;链接。用户可以点击这个链接来删除某个联系人信息。</span></p>
<p style="text-indent: -21pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span> <font size="2">4.</font> </span></span><span style="font-family: 宋体">如果有管理权限，用户可以看到在联系人后面有一个&#8220;</span><span lang="EN-US">Admin Permission</span><span style="font-family: 宋体">&#8221;链接。用户可以点击这个链接来管理访问这个联系人的权限。例如，</span></p>
<h1><span lang="EN-US" style="font-size: 12pt"><font face="宋体">Administer Permissions</font></span></h1>
<p><code><span lang="EN-US" style="font-size: 10pt; font-family: 黑体">sample.contact.Contact@26807f: Id: 1; Name: John Smith; Email: john@somewhere.com </span></code></p>
<table cellpadding="0" border="0">
    <tbody>
        <tr>
            <td style="border-right: rgb(212,208,200); padding-right: 2.25pt; border-top: rgb(212,208,200); padding-left: 2.25pt; padding-bottom: 2.25pt; border-left: rgb(212,208,200); padding-top: 2.25pt; border-bottom: rgb(212,208,200); background-color: transparent">
            <p><code><span lang="EN-US" style="font-size: 10pt; font-family: 黑体">-R--- [2] dianne </span></code></p>
            </td>
            <td style="border-right: rgb(212,208,200); padding-right: 2.25pt; border-top: rgb(212,208,200); padding-left: 2.25pt; padding-bottom: 2.25pt; border-left: rgb(212,208,200); padding-top: 2.25pt; border-bottom: rgb(212,208,200); background-color: transparent">
            <p><span lang="EN-US"><a href="http://localhost:8080/acegi-security-sample-contacts-filter/secure/deletePermission.htm?contactId=1&amp;recipient=dianne">Del</a> </span></p>
            </td>
        </tr>
        <tr>
            <td style="border-right: rgb(212,208,200); padding-right: 2.25pt; border-top: rgb(212,208,200); padding-left: 2.25pt; padding-bottom: 2.25pt; border-left: rgb(212,208,200); padding-top: 2.25pt; border-bottom: rgb(212,208,200); background-color: transparent">
            <p><code><span lang="EN-US" style="font-size: 10pt; font-family: 黑体">-RW-D [22] peter </span></code></p>
            </td>
            <td style="border-right: rgb(212,208,200); padding-right: 2.25pt; border-top: rgb(212,208,200); padding-left: 2.25pt; padding-bottom: 2.25pt; border-left: rgb(212,208,200); padding-top: 2.25pt; border-bottom: rgb(212,208,200); background-color: transparent">
            <p><span lang="EN-US"><a href="http://localhost:8080/acegi-security-sample-contacts-filter/secure/deletePermission.htm?contactId=1&amp;recipient=peter">Del</a> </span></p>
            </td>
        </tr>
        <tr>
            <td style="border-right: rgb(212,208,200); padding-right: 2.25pt; border-top: rgb(212,208,200); padding-left: 2.25pt; padding-bottom: 2.25pt; border-left: rgb(212,208,200); padding-top: 2.25pt; border-bottom: rgb(212,208,200); background-color: transparent">
            <p><code><span lang="EN-US" style="font-size: 10pt; font-family: 黑体">A---- [1] marissa </span></code></p>
            </td>
            <td style="border-right: rgb(212,208,200); padding-right: 2.25pt; border-top: rgb(212,208,200); padding-left: 2.25pt; padding-bottom: 2.25pt; border-left: rgb(212,208,200); padding-top: 2.25pt; border-bottom: rgb(212,208,200); background-color: transparent">
            <p><span lang="EN-US"><a href="http://localhost:8080/acegi-security-sample-contacts-filter/secure/deletePermission.htm?contactId=1&amp;recipient=marissa">Del</a> </span></p>
            </td>
        </tr>
    </tbody>
</table>
<p><span lang="EN-US"><a href="http://localhost:8080/acegi-security-sample-contacts-filter/secure/addPermission.htm?contactId=1"><font face="宋体" size="3">Add Permission</font></a><font face="宋体" size="3"> </font><a href="http://localhost:8080/acegi-security-sample-contacts-filter/secure/index.htm"><font face="宋体" size="3">Manage</font></a><font face="宋体" size="3"> </font></span></p>
<p><span style="font-family: 宋体">说明：每一行记录包含有</span><span lang="EN-US">3</span><span style="font-family: 宋体">列。</span></p>
<p><span style="font-family: 宋体">第一列表示权限，例如，&#8220;</span><code><span lang="EN-US" style="font-size: 10pt; font-family: 黑体">-RW-D</span></code><span style="font-family: 宋体">&#8221;表示可读、可写、可删除。</span></p>
<p><span style="font-family: 宋体">第二列也表示权限，但它是以类似</span><span lang="EN-US">unix</span><span style="font-family: 宋体">权限的数字表达。例如，&#8220;</span><span lang="EN-US">[22]</span><span style="font-family: 宋体">&#8221;</span><span lang="EN-US">, </span><span style="font-family: 宋体">表示可读、可写、可删除。</span></p>
<p><span style="font-family: 宋体">第三列是用户名称。</span></p>
<p><span style="font-family: 宋体">每一行记录后面都有一个&#8220;</span><span lang="EN-US">Del</span><span style="font-family: 宋体">&#8221;链接。点击这个链接，可以删除掉指定用户对这个联系人信息的权限。</span></p>
<p style="text-indent: -21pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span> <font size="2">5.</font> </span></span><span style="font-family: 宋体">用户可以为某个联系人信息添加权限。例如，</span></p>
<h1><span lang="EN-US" style="font-size: 12pt"><font face="宋体">Add Permission</font></span></h1>
<form>
    <table style="width: 95%" cellspacing="0" cellpadding="0" width="95%" bgcolor="#f8f8ff" border="0">
        <tbody>
            <tr>
                <td style="border-right: rgb(212,208,200); padding-right: 3.75pt; border-top: rgb(212,208,200); padding-left: 3.75pt; padding-bottom: 3.75pt; border-left: rgb(212,208,200); width: 20%; padding-top: 3.75pt; border-bottom: rgb(212,208,200); background-color: transparent" width="20%">
                <p><span lang="EN-US">Contact:</span></p>
                </td>
                <td style="border-right: rgb(212,208,200); padding-right: 3.75pt; border-top: rgb(212,208,200); padding-left: 3.75pt; padding-bottom: 3.75pt; border-left: rgb(212,208,200); width: 60%; padding-top: 3.75pt; border-bottom: rgb(212,208,200); background-color: transparent" width="60%">
                <p><span lang="EN-US">sample.contact.Contact@1787005: Id: 1; Name: John Smith; Email: john@somewhere.com</span></p>
                </td>
                <td style="border-right: rgb(212,208,200); padding-right: 0cm; border-top: rgb(212,208,200); padding-left: 0cm; padding-bottom: 0cm; border-left: rgb(212,208,200); padding-top: 0cm; border-bottom: rgb(212,208,200); background-color: transparent" width="328">
                <p>&nbsp;</p>
                <br />
                </td>
            </tr>
            <tr>
                <td style="border-right: rgb(212,208,200); padding-right: 3.75pt; border-top: rgb(212,208,200); padding-left: 3.75pt; padding-bottom: 3.75pt; border-left: rgb(212,208,200); width: 20%; padding-top: 3.75pt; border-bottom: rgb(212,208,200); background-color: transparent" width="20%">
                <p><span lang="EN-US">Recipient:</span></p>
                </td>
                <td style="border-right: rgb(212,208,200); padding-right: 3.75pt; border-top: rgb(212,208,200); padding-left: 3.75pt; padding-bottom: 3.75pt; border-left: rgb(212,208,200); width: 20%; padding-top: 3.75pt; border-bottom: rgb(212,208,200); background-color: transparent" width="20%">
                <p><span lang="EN-US"><select name="recipient">
                <option selected>-- please select --</option>
                <option value="dianne">dianne</option>
                <option value="marissa">marissa</option>
                <option value="peter">peter</option>
                <option value="scott">scott</option>
                <option value="ROLE_SUPERVISOR">ROLE_SUPERVISOR</option>
                <option value="ROLE_USER">ROLE_USER</option>
                </select></span></p>
                </td>
                <td style="border-right: rgb(212,208,200); padding-right: 3.75pt; border-top: rgb(212,208,200); padding-left: 3.75pt; padding-bottom: 3.75pt; border-left: rgb(212,208,200); width: 60%; padding-top: 3.75pt; border-bottom: rgb(212,208,200); background-color: transparent" width="60%">
                <p>&nbsp;</p>
                <br />
                </td>
            </tr>
            <tr>
                <td style="border-right: rgb(212,208,200); padding-right: 3.75pt; border-top: rgb(212,208,200); padding-left: 3.75pt; padding-bottom: 3.75pt; border-left: rgb(212,208,200); width: 20%; padding-top: 3.75pt; border-bottom: rgb(212,208,200); background-color: transparent" width="20%">
                <p><span lang="EN-US">Permission:</span></p>
                </td>
                <td style="border-right: rgb(212,208,200); padding-right: 3.75pt; border-top: rgb(212,208,200); padding-left: 3.75pt; padding-bottom: 3.75pt; border-left: rgb(212,208,200); width: 20%; padding-top: 3.75pt; border-bottom: rgb(212,208,200); background-color: transparent" width="20%">
                <p><span lang="EN-US"><select name="permission">
                <option value="0" selected>None</option>
                <option value="1">Administer</option>
                <option value="2">Read</option>
                <option value="16">Delete</option>
                <option value="22">Read+Write+Delete</option>
                </select></span></p>
                </td>
                <td style="border-right: rgb(212,208,200); padding-right: 3.75pt; border-top: rgb(212,208,200); padding-left: 3.75pt; padding-bottom: 3.75pt; border-left: rgb(212,208,200); padding-top: 3.75pt; border-bottom: rgb(212,208,200); background-color: transparent">
                <p>&nbsp;</p>
                <br />
                </td>
            </tr>
        </tbody>
    </table>
</form>
<span style="font-size: 9pt; font-family: 宋体">说明：权限是动态添加的。例如，上图中给用户</span><span lang="EN-US" style="font-size: 9pt; font-family: 'Times New Roman'">scott</span><span style="font-size: 9pt; font-family: 宋体">增加了读联系人</span><span lang="EN-US" style="font-size: 9pt; font-family: 'Times New Roman'">John</span><span style="font-size: 9pt; font-family: 宋体">的权限。那么</span><span lang="EN-US" style="font-size: 9pt; font-family: 'Times New Roman'">scott</span><span style="font-size: 9pt; font-family: 宋体">马上就可以看到联系人</span><span lang="EN-US" style="font-size: 9pt; font-family: 'Times New Roman'">John</span><span style="font-size: 9pt; font-family: 宋体">的信息了。</span></span> 
<img src ="http://www.blogjava.net/szhswl/aggbug/168837.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/szhswl/" target="_blank">宋针还</a> 2007-12-19 19:43 <a href="http://www.blogjava.net/szhswl/articles/168837.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>