Acegi好早就實現了ACL(好像是0.5),但是使用起來確實有點麻煩,所以用的不是太廣泛。這里簡單的說明一下使用方法,希望有更多的朋友來試試。
首先要理解Acegi里面Voter的概念,ACL正是在一個Voter上擴展起來的。現來看一下AclVoter的配置。
????<bean?id="aclBeanReadVoter"?class="org.acegisecurity.vote.BasicAclEntryVoter">
????????<property?name="processConfigAttribute">
????????????<value>ACL_READ</value>
????????</property>
????????<property?name="processDomainObjectClass">
????????????<value>org.springside.modules.security.acl.domain.AclDomainAware</value>
????????</property>
????????<property?name="aclManager">
????????????<ref?local="aclManager"/>
????????</property>
????????<property?name="requirePermission">
????????????<list>
????????????????<ref?local="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
????????????????<ref?local="org.acegisecurity.acl.basic.SimpleAclEntry.READ"/>
????????????</list>
????????</property>
????</bean>- ACL_READ指的是這個Voter對哪些SecurityConfig起作用,我們可以把ACL_READ配置在想要攔截的Method上。比方說我們要攔截readOrder這個方法,以實現ACL控制,可以這樣配置。
orderManager.readOrder=ACL_READ - processDomainObjectClass指出哪些DomainObject是要進行ACL校驗的。
- aclManager是一個比較重要的概念,主要負責在權限列表中根據用戶和DomainObject取得acl列表。
- requirePermission指出要進行這個操作必須具備的acl權限,比方說read操作就必須有ADMINISTRATION或READ兩個權限。
其實整個過程看下來比較清晰,下面來看一下AclManager如何配置。
????<!--?=========?ACCESS?CONTROL?LIST?LOOKUP?MANAGER?DEFINITIONS?=========?-->

????<bean?id="aclManager"?class="org.acegisecurity.acl.AclProviderManager">
????????<property?name="providers">
????????????<list>
????????????????<ref?local="basicAclProvider"/>
????????????</list>
????????</property>
????</bean>

????<bean?id="basicAclProvider"?class="org.acegisecurity.acl.basic.BasicAclProvider">
????????<property?name="basicAclDao">
????????????<ref?local="basicAclExtendedDao"/>
????????</property>
????</bean>

????<bean?id="basicAclExtendedDao"?class="org.acegisecurity.acl.basic.jdbc.JdbcExtendedDaoImpl">
????????<property?name="dataSource">
????????????<ref?bean="dataSource"/>
????????</property>
????</bean>很明顯ACLManager繼承了Acegi的一貫風格,Provider可以提供多種取得ACL訪問列表的途徑,默認的是用
basicAclProvider在數據庫中取得。既然提到了數據庫,那我們就來看一下Acegi默認提供的ACL在數據庫里的保存表結構:
CREATE?TABLE?acl_object_identity?(
id?IDENTITY?NOT?NULL,
object_identity?VARCHAR_IGNORECASE(250)?NOT?NULL,
parent_object?INTEGER,
acl_class?VARCHAR_IGNORECASE(250)?NOT?NULL,
CONSTRAINT?unique_object_identity?UNIQUE(object_identity),
FOREIGN?KEY?(parent_object)?REFERENCES?acl_object_identity(id)
);
CREATE?TABLE?acl_permission?(
id?IDENTITY?NOT?NULL,
acl_object_identity?INTEGER?NOT?NULL,
recipient?VARCHAR_IGNORECASE(100)?NOT?NULL,
mask?INTEGER?NOT?NULL,
CONSTRAINT?unique_recipient?UNIQUE(acl_object_identity,?recipient),
FOREIGN?KEY?(acl_object_identity)?REFERENCES?acl_object_identity(id)
);- acl_object_identity表存放了所有受保護的domainObject的信息。其中object_identity字段保存了domainObject的class和id,默認的保存格式是:domainClass:domainObjectId。
- acl_permission?就是ACL權限列表了,recipient?是用戶或角色信息,mask表示了這個用戶或角色對這個domainObject的訪問權限。注意這些信息的保存格式都是可以根據自己的需要改變的。
這樣讀取和刪除的時候Acegi就能很好的完成攔截工作,但是讀取一個List的時候,如何才能把該用戶不能操作的domainObject剔除掉呢?這就需要afterInvocationManager來完成這個工作。下面來看下配置:
????<!--?==============?"AFTER?INTERCEPTION"?AUTHORIZATION?DEFINITIONS?===========?-->

????<bean?id="afterInvocationManager"?class="org.acegisecurity.afterinvocation.AfterInvocationProviderManager">
????????<property?name="providers">
????????????<list>
????????????????<ref?local="afterAclCollectionRead"/>
????????????</list>
????????</property>
????</bean>
????<!--?Processes?AFTER_ACL_COLLECTION_READ?configuration?settings?-->
????<bean?id="afterAclCollectionRead"?class="org.acegisecurity.afterinvocation.BasicAclEntryAfterInvocationCollectionFilteringProvider">
????????<property?name="aclManager">
????????????<ref?local="aclManager"/>
????????</property>
????????<property?name="requirePermission">
????????????<list>
????????????????<ref?local="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
????????????????<ref?local="org.acegisecurity.acl.basic.SimpleAclEntry.READ"/>
????????????</list>
????????</property>
????</bean> afterAclCollectionRead會在攔截的方法執行結束的時候執行。主要的作用就是在返回的List中挨個檢查domainObject的操作權限,然后根據requirePermission來剔除不符合的domainObject。
posted @
2006-06-17 00:20 差沙 閱讀(2276) |
評論 (4) |
編輯 收藏
acegi1.0發布,其實有點出乎意料,因為我一向認為acegi的代碼已經相當穩定了,但是acegi力求精益求精,從新版還是能看到不少實用的改動和升級。這里簡單分析一下。
[SEC-183] - Avoid unnecessary HttpSession creation when using Anonymous and Remember-Me authentication
以前如果使用HttpSessionContextIntegrationFilter的話,不管你是否需要創建session,他都會給你創建。這在一些Base驗證的時候是多余的。現在加上了forceEagerSessionCreation,在創建session的時候做了控制。
[SEC-29] - Save POST request parameters before redirect
在前幾個版本出現這個問題,如果實現了登陸自動跳轉,acegi僅僅是簡單記錄了URL,沒有深入的紀錄信息。新版本中acegi不僅僅是保持POST中的數據不會丟失,request里面的東西幾乎全都序列化保存下來了,實現可以看看SavedRequest。
[SEC-40] - HibernateDao.scroll() performance
[SEC-92] - Hibernate ACL implementation
這個比較激動的改進在1.0的源碼中沒有找到,看alex的意思好像是僅僅提供各演示,目的是為了生成數據腳本方便點。(其實這個還真的沒法做成特別通用的,畢竟每個人的ACL實現都有可能不同)
[SEC-147] - BasicAclEntryAfterInvocationProvider should support processDomainObjectClass
對List進行ACL交驗的時候,會把第一個元素取出,看看是否AssignableFrom這個processDomainObjectClass ,算是做一下安全檢查吧。
[SEC-172] - Allow SimpleAclEntry to take 'null' as recipient constructor argument
其實應該是不允許recipient 為空。
[SEC-187] - inHttp & inHttps not fully utilized in AuthenticationProcessingFilterEntryPoint
[SEC-191] - AclTag class should use the BeanFactoryUtils.beanNamesForTypeIncludingAncestors method to search for the AclManager
AclTag在尋找AclManager 時候會更加靈活了,得益于spring的強大。
<明天繼續吧。。。。>
[SEC-194] - RememberMeServices should be available when using BasicAuth logins
[SEC-195] - Create Acegi-backed CAS3 AuthenticationHandler
[SEC-196] - Update web site and documentation to reference JA-SIG CAS
[SEC-203] - Allow setting the AuthenticationManager onto the ConcurrentSessionController for inverted dependency
[SEC-204] - Better detection of malformed text in FilterInvocationDefinitionSourceEditor
[SEC-205] - Allow multiple URLs in DefaultInitialDirContextFactory
[SEC-206] - TokenBasedRememberMeServices using context root when setting cookie paths (inc code)
[SEC-207] - Implement countermeasures against session attacks
[SEC-209] - Make AbstractProcessingFilter.eventPublisher field protected
[SEC-217] - Improve Siteminder Filter
[SEC-220] - Allow ExceptionTranslationFilter to not catch exceptions
[SEC-221] - AbstractProcessingFilter.onPreAuthentication exceptions should be caught
[SEC-224] - Make Authentication.getPrincipal() for CAS return the UserDetails
[SEC-229] - Allow redirects to external URLs in AbstractProcessingFilter
[SEC-231] - Add another DefaultLdapAuthoritiesPopulator.getGroupMembershipRoles
[SEC-234] - Allow WebAuthenticationDetails pluggable implementations
[SEC-236] - JbossAcegiLoginModule to use ApplicationContext interface
[SEC-238] - Add AuthenticationException to AbstractProcessingFilter.onUnsuccessfulAuthentication method signature
[SEC-242] - Logger in AbstractProcessingFilter
[SEC-244] - Column names instead of indexes for org.acegisecurity.userdetails.jdbc.JdbcDaoImpl
[SEC-246] - Enable late-binding of UserDetailsService on DaoAuthenticationProvider
[SEC-247] - Allow to specify resources that shouldn't be filtered in FilterChainProxy
[SEC-251] - DefaultLdapAuthoritiesPopulator: Add filter argument {1} for username as in Tomcat JNDIRealm
[SEC-255] - Reorder AuthenticationProcessingFilter to create HttpSession before delegating to AuthenticationDetailsSource
[SEC-257] - ExceptionTranslationFilter to use strategy interface for AccessDeniedException handling
[SEC-259] - AccessDecisionVoter: typo in JavaDoc
[SEC-260] - AbstractAccessDecisionManager and loggers
[SEC-262] - AbstractAccessDecisionManager needs standard handling ifAllAbstainDecisions
[SEC-264] - Introduction of LdapUserDetails and changes to LdapAuthenticator and LdapAuthoritiesPopulator interfaces
[SEC-276] - Restructure reference guide
posted @
2006-06-01 23:05 差沙 閱讀(559) |
評論 (0) |
編輯 收藏
這兩天在
springside受白衣的影響開始關注drools。說他是平民的腳本引擎一點都不假,使用起來極為方便,本來以為網上應該有不少的講解了,但是發現幾乎全是針對2.0版本講解的。而drools加入jboss后有了質的變化,下面來看一下最新的3.0使用起來有什么不同:
首先我們要取得rule,規則引擎、規則引擎,取得規則是必要的。

private?static?RuleBase?readRule()?throws?Exception?
{
????????//read?in?the?source
????????Reader?source?=?new?InputStreamReader(?DroolsTest.class.getResourceAsStream(?"/aclcreat.drl"?)?);
????????
????????//optionally?read?in?the?DSL?(if?you?are?using?it).
????????Reader?dsl?=?new?InputStreamReader(?DroolsTest.class.getResourceAsStream(?"/mylang.dsl"?)?);

????????//Use?package?builder?to?build?up?a?rule?package.
????????//An?alternative?lower?level?class?called?"DrlParser"?can?also?be?used
????????
????????PackageBuilder?builder?=?new?PackageBuilder();

????????//this?wil?parse?and?compile?in?one?step
????????//NOTE:?There?are?2?methods?here,?the?one?argument?one?is?for?normal?DRL.
????????//builder.addPackageFromDrl(?source?);

????????//Use?the?following?instead?of?above?if?you?are?using?a?DSL:
????????builder.addPackageFromDrl(?source,?dsl?);
????????
????????//get?the?compiled?package?(which?is?serializable)
????????Package?pkg?=?builder.getPackage();
????????
????????//add?the?package?to?a?rulebase?(deploy?the?rule?package).
????????RuleBase?ruleBase?=?RuleBaseFactory.newRuleBase();
????????ruleBase.addPackage(?pkg?);
????????return?ruleBase;
????}這里在官方的例子基礎上做了自己的實現(其實什么都沒改)。
可以看到,第一步是取得文件IO,這個文件就是我們要寫得規則腳本,這個等下再說,大家可以假象一下腳本是個什么樣子,現在只說怎么在程序中取得Rule。
接下來,是使用Builder取得一個package,既然builder都上來了說明能輸入的腳本不止一個了。用addPackageFromDrl向這個builder壓縮機里面輸入腳本,當然還有另外一個文件dsl,這個后面再說。利用builder取得package。
最后構造一個BaseRule,利用Factory取得的時候是有選擇的,RuleBaseFactory.newRuleBase(int type)其中的type可以為不同的Algorithm,有RETE和Leaps 兩種。對這兩種Algorithm的具體解釋可以參看
http://citeseer.ist.psu.edu/context/505087/0?或是 drools的文檔,其實我也不太懂。
把剛才的package添到ruleBase里面一個Rule就大功告成了。
接下來看看怎么執行它:
????????????WorkingMemory?workingMemory?=?ruleBase.newWorkingMemory();
????????????
????????????//go?!
????????????Order?order?=?new?Order();
????????????order.setId(1);
????????????order.setName("testOrder");
????????????order.setTotlePrice(10);
????????????????????????
????????????User?user?=?new?User();
????????????user.setName("testAdmin");
????????????user.setAuth("USER_ADMIN");
????????????List<String>?roles?=?new?ArrayList<String>();
????????????roles.add("ADMIN");
????????????user.setRoles(roles);
????????????

????????????User?user1?=?new?User();
????????????user1.setName("testUser");
????????????user1.setAuth("USER_USER");
????????????List<String>?roles1?=?new?ArrayList<String>();
????????????roles1.add("USER");
????????????user1.setRoles(roles1);
????????????
????????????workingMemory.assertObject(order);
????????????workingMemory.assertObject(user);
????????????workingMemory.assertObject(user1);
????????????
????????????workingMemory.fireAllRules();????????
????????????
????????????List<AclEntry>?acls?=?workingMemory.getObjects(AclEntry.class);用ruleBase生成一個WorkingMemory,WorkingMemory是Rule的執行引擎,裝載rule和事實(很重要的概念),并統一執行他們。接下來我就在寫我的事實,事實是什么,事實就是今天是什么天?訂單總價多少?就是要告訴腳本的java對象。然后把事實一一壓入WorkingMemory這個大壓縮機。就瞧好吧。
OK可以執行了,fireAllRules!(真TM,COOL的名字)。當然有全部執行就有部分執行。你可以把規則分組,然后按組執行,或是指定rule的名字來執行(這里還是大家自己看看吧)。
???究竟執行了什么。當然是執行了我們的腳本,腳本在這里、看看它可不是xml了:
#created?on:?2006-5-19
package?com.sample;

#list?any?import?classes?here.

import?com.sample.domain.Order;
import?com.sample.domain.User;

import?com.sample.AclEntry;
#expander?mylang.dsl

#declare?any?global?variables?here

rule?"Order?TotlePrice?more?than?$1000"????
????when
????????#conditions
????????$order?:?Order(?totlePrice?>?1000?)
????????$user?:?User(?roles?contains?"ADMIN"?,?$userName?:?name)
????then?
????????#actions
????????System.out.println("More?Than");
????????assert(new?AclEntry($order,?$user,?1));
end

rule?"Order?TotlePrice?less?or?equl?than?$1000"????
????when
????????#conditions
????????$order?:?Order(?totlePrice?<=?1000?)
????????$user?:?User(?$userName?:?name?)
????then?
????????#actions
????????System.out.println("Less?Than");
????????assert(new?AclEntry($order,?$user,?2));
end每一個rule就是一個規則,所有的事實要一一過一遍這些規則。when是規則提出的條件,如果哪個事實符合這個條件,就進入then的環節,進行相應的處理。
分析一下條件:$order?:?Order(?totlePrice?
>?1000?)。一看就知道是總價超過1000的訂單。$order是把這個訂單邦定,后面可以使用。
分析一下then:?System.out.println就不解釋了。assert(new?AclEntry($order,?$user,?2)); 這里的assert的意義就是告訴WorkingMemory一個事實,其實跟前面的加入事實一個道理。打個比方,如果有閃電,那么就有雷。
這樣走完一個rule后大家很容易發現,其實是根據訂單和用戶的角色不同產生了不同的acl,然后我要拿到這些由事實得到的事實。
List<AclEntry>?acls?=?workingMemory.getObjects(AclEntry.class);這樣就能在workingMemory里面掏出我們需要的事實來,新鮮出爐的哦。
相當粗略的講了一下drools,目的是希望大家都來了解一下,共同學習。
posted @
2006-05-28 20:53 差沙 閱讀(2842) |
評論 (9) |
編輯 收藏
以前不寫blog,很多技術學完就忘了。總是反復請教google,慚愧的很。決心以后記錄自己技術的點點滴滴了。
posted @
2006-05-27 22:52 差沙 閱讀(473) |
評論 (0) |
編輯 收藏