Acegi好早就實(shí)現(xiàn)了ACL(好像是0.5),但是使用起來確實(shí)有點(diǎn)麻煩,所以用的不是太廣泛。這里簡單的說明一下使用方法,希望有更多的朋友來試試。
首先要理解Acegi里面Voter的概念,ACL正是在一個(gè)Voter上擴(kuò)展起來的。現(xiàn)來看一下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指的是這個(gè)Voter對哪些SecurityConfig起作用,我們可以把ACL_READ配置在想要攔截的Method上。比方說我們要攔截readOrder這個(gè)方法,以實(shí)現(xiàn)ACL控制,可以這樣配置。
orderManager.readOrder=ACL_READ - processDomainObjectClass指出哪些DomainObject是要進(jìn)行ACL校驗(yàn)的。
- aclManager是一個(gè)比較重要的概念,主要負(fù)責(zé)在權(quán)限列表中根據(jù)用戶和DomainObject取得acl列表。
- requirePermission指出要進(jìn)行這個(gè)操作必須具備的acl權(quán)限,比方說read操作就必須有ADMINISTRATION或READ兩個(gè)權(quán)限。
其實(shí)整個(gè)過程看下來比較清晰,下面來看一下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的一貫風(fēng)格,Provider可以提供多種取得ACL訪問列表的途徑,默認(rèn)的是用
basicAclProvider在數(shù)據(jù)庫中取得。既然提到了數(shù)據(jù)庫,那我們就來看一下Acegi默認(rèn)提供的ACL在數(shù)據(jù)庫里的保存表結(jié)構(gòu):
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表存放了所有受保護(hù)的domainObject的信息。其中object_identity字段保存了domainObject的class和id,默認(rèn)的保存格式是:domainClass:domainObjectId。
- acl_permission?就是ACL權(quán)限列表了,recipient?是用戶或角色信息,mask表示了這個(gè)用戶或角色對這個(gè)domainObject的訪問權(quán)限。注意這些信息的保存格式都是可以根據(jù)自己的需要改變的。
這樣讀取和刪除的時(shí)候Acegi就能很好的完成攔截工作,但是讀取一個(gè)List的時(shí)候,如何才能把該用戶不能操作的domainObject剔除掉呢?這就需要afterInvocationManager來完成這個(gè)工作。下面來看下配置:
????<!--?==============?"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會在攔截的方法執(zhí)行結(jié)束的時(shí)候執(zhí)行。主要的作用就是在返回的List中挨個(gè)檢查domainObject的操作權(quán)限,然后根據(jù)requirePermission來剔除不符合的domainObject。
posted @
2006-06-17 00:20 差沙 閱讀(2283) |
評論 (4) |
編輯 收藏
acegi1.0發(fā)布,其實(shí)有點(diǎn)出乎意料,因?yàn)槲乙幌蛘J(rèn)為acegi的代碼已經(jīng)相當(dāng)穩(wěn)定了,但是acegi力求精益求精,從新版還是能看到不少實(shí)用的改動和升級。這里簡單分析一下。
[SEC-183] - Avoid unnecessary HttpSession creation when using Anonymous and Remember-Me authentication
以前如果使用HttpSessionContextIntegrationFilter的話,不管你是否需要?jiǎng)?chuàng)建session,他都會給你創(chuàng)建。這在一些Base驗(yàn)證的時(shí)候是多余的。現(xiàn)在加上了forceEagerSessionCreation,在創(chuàng)建session的時(shí)候做了控制。
[SEC-29] - Save POST request parameters before redirect
在前幾個(gè)版本出現(xiàn)這個(gè)問題,如果實(shí)現(xiàn)了登陸自動跳轉(zhuǎn),acegi僅僅是簡單記錄了URL,沒有深入的紀(jì)錄信息。新版本中acegi不僅僅是保持POST中的數(shù)據(jù)不會丟失,request里面的東西幾乎全都序列化保存下來了,實(shí)現(xiàn)可以看看SavedRequest。
[SEC-40] - HibernateDao.scroll() performance
[SEC-92] - Hibernate ACL implementation
這個(gè)比較激動的改進(jìn)在1.0的源碼中沒有找到,看alex的意思好像是僅僅提供各演示,目的是為了生成數(shù)據(jù)腳本方便點(diǎn)。(其實(shí)這個(gè)還真的沒法做成特別通用的,畢竟每個(gè)人的ACL實(shí)現(xiàn)都有可能不同)
[SEC-147] - BasicAclEntryAfterInvocationProvider should support processDomainObjectClass
對List進(jìn)行ACL交驗(yàn)的時(shí)候,會把第一個(gè)元素取出,看看是否AssignableFrom這個(gè)processDomainObjectClass ,算是做一下安全檢查吧。
[SEC-172] - Allow SimpleAclEntry to take 'null' as recipient constructor argument
其實(shí)應(yīng)該是不允許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 時(shí)候會更加靈活了,得益于spring的強(qiáng)大。
<明天繼續(xù)吧。。。。>
[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 差沙 閱讀(563) |
評論 (0) |
編輯 收藏
這兩天在
springside受白衣的影響開始關(guān)注drools。說他是平民的腳本引擎一點(diǎn)都不假,使用起來極為方便,本來以為網(wǎng)上應(yīng)該有不少的講解了,但是發(fā)現(xiàn)幾乎全是針對2.0版本講解的。而drools加入jboss后有了質(zhì)的變化,下面來看一下最新的3.0使用起來有什么不同:
首先我們要取得rule,規(guī)則引擎、規(guī)則引擎,取得規(guī)則是必要的。

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;
????}這里在官方的例子基礎(chǔ)上做了自己的實(shí)現(xiàn)(其實(shí)什么都沒改)。
可以看到,第一步是取得文件IO,這個(gè)文件就是我們要寫得規(guī)則腳本,這個(gè)等下再說,大家可以假象一下腳本是個(gè)什么樣子,現(xiàn)在只說怎么在程序中取得Rule。
接下來,是使用Builder取得一個(gè)package,既然builder都上來了說明能輸入的腳本不止一個(gè)了。用addPackageFromDrl向這個(gè)builder壓縮機(jī)里面輸入腳本,當(dāng)然還有另外一個(gè)文件dsl,這個(gè)后面再說。利用builder取得package。
最后構(gòu)造一個(gè)BaseRule,利用Factory取得的時(shí)候是有選擇的,RuleBaseFactory.newRuleBase(int type)其中的type可以為不同的Algorithm,有RETE和Leaps 兩種。對這兩種Algorithm的具體解釋可以參看
http://citeseer.ist.psu.edu/context/505087/0?或是 drools的文檔,其實(shí)我也不太懂。
把剛才的package添到ruleBase里面一個(gè)Rule就大功告成了。
接下來看看怎么執(zhí)行它:
????????????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生成一個(gè)WorkingMemory,WorkingMemory是Rule的執(zhí)行引擎,裝載rule和事實(shí)(很重要的概念),并統(tǒng)一執(zhí)行他們。接下來我就在寫我的事實(shí),事實(shí)是什么,事實(shí)就是今天是什么天?訂單總價(jià)多少?就是要告訴腳本的java對象。然后把事實(shí)一一壓入WorkingMemory這個(gè)大壓縮機(jī)。就瞧好吧。
OK可以執(zhí)行了,fireAllRules!(真TM,COOL的名字)。當(dāng)然有全部執(zhí)行就有部分執(zhí)行。你可以把規(guī)則分組,然后按組執(zhí)行,或是指定rule的名字來執(zhí)行(這里還是大家自己看看吧)。
???究竟執(zhí)行了什么。當(dāng)然是執(zhí)行了我們的腳本,腳本在這里、看看它可不是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每一個(gè)rule就是一個(gè)規(guī)則,所有的事實(shí)要一一過一遍這些規(guī)則。when是規(guī)則提出的條件,如果哪個(gè)事實(shí)符合這個(gè)條件,就進(jìn)入then的環(huán)節(jié),進(jìn)行相應(yīng)的處理。
分析一下條件:$order?:?Order(?totlePrice?
>?1000?)。一看就知道是總價(jià)超過1000的訂單。$order是把這個(gè)訂單邦定,后面可以使用。
分析一下then:?System.out.println就不解釋了。assert(new?AclEntry($order,?$user,?2)); 這里的assert的意義就是告訴WorkingMemory一個(gè)事實(shí),其實(shí)跟前面的加入事實(shí)一個(gè)道理。打個(gè)比方,如果有閃電,那么就有雷。
這樣走完一個(gè)rule后大家很容易發(fā)現(xiàn),其實(shí)是根據(jù)訂單和用戶的角色不同產(chǎn)生了不同的acl,然后我要拿到這些由事實(shí)得到的事實(shí)。
List<AclEntry>?acls?=?workingMemory.getObjects(AclEntry.class);這樣就能在workingMemory里面掏出我們需要的事實(shí)來,新鮮出爐的哦。
相當(dāng)粗略的講了一下drools,目的是希望大家都來了解一下,共同學(xué)習(xí)。
posted @
2006-05-28 20:53 差沙 閱讀(2853) |
評論 (9) |
編輯 收藏
以前不寫blog,很多技術(shù)學(xué)完就忘了。總是反復(fù)請教google,慚愧的很。決心以后記錄自己技術(shù)的點(diǎn)點(diǎn)滴滴了。
posted @
2006-05-27 22:52 差沙 閱讀(479) |
評論 (0) |
編輯 收藏