14.1 Acegi眼中的領(lǐng)域?qū)ο?/h3>
大部分開發(fā)者都應(yīng)該熟悉基于Windows NT內(nèi)核的Windows操作系統(tǒng),比如Windows 2000、2003、XP。事實(shí)上,Windows操作系統(tǒng)本身充當(dāng)了管理千萬個(gè)領(lǐng)域?qū)ο蟮慕巧@里的領(lǐng)域?qū)ο缶褪悄切┪募A和文件。各個(gè)文件夾可以含有子文件夾,也可以含有大量的文件。文件是葉節(jié)點(diǎn),它不再包含任何子元素。從領(lǐng)域?qū)ο蟮慕嵌瘸霭l(fā),文件夾和文件自身都持有各自的訪問控制列表(Access Control List,ACL),ACL用于給定操控這些領(lǐng)域?qū)ο蟮臋?quán)限信息,比如marissa用戶可以操作shared目錄,而scott用戶不能夠操作shared目錄等。
為了同基于角色授權(quán)區(qū)分開,對于領(lǐng)域?qū)ο蠖裕L問控制列表(Access Control List,ACL)成為了各個(gè)領(lǐng)域?qū)ο蟮?#8220;專有名詞”。這意味著,角色授權(quán)適用于Web資源和業(yè)務(wù)方法,而ACL授權(quán)適用于領(lǐng)域?qū)ο蟆8鱾€(gè)ACL可能持有若干個(gè)ACE,即Access Control Entry(訪問控制項(xiàng))。總之,各個(gè)領(lǐng)域?qū)ο蠖紩?huì)存在對應(yīng)它的ACL,而各個(gè)ACL會(huì)持有若干個(gè)ACE,ACE真正給出了操控當(dāng)前領(lǐng)域?qū)ο蟮木唧w權(quán)限信息。
關(guān)于org.acegisecurity.acl與org.acegisecurity.acls包
|
早期的Acegi就提供了較好的領(lǐng)域?qū)ο笾С郑磑rg.acegisecurity.acl包。隨著企業(yè)用戶的日益使用,他們逐漸認(rèn)識(shí)到org.acegisecurity.acl的不足之處,比如他們不能夠?qū)⑻囟〝?shù)據(jù)庫提供的一些高級(jí)特性應(yīng)用到自身的應(yīng)用中、acl包操作數(shù)據(jù)庫的效率較低、對內(nèi)存的使用不是非常合理等。后來,Acegi開發(fā)團(tuán)隊(duì)便也在逐漸改進(jìn)現(xiàn)有的不足之處。
自從Acegi 1.0.3開始,基于新基代碼的org.acegisecurity.acls包取代了org.acegisecurity.acl的地位,也就是說新開發(fā)的企業(yè)應(yīng)用最好使用org.acegisecurity.acls提供的領(lǐng)域?qū)ο笾С帧1緯鴥H僅專注org.acegisecurity.acls的使用,這兩個(gè)包的使用存在的差別很大。可以看出,acls包不僅克服了原有acl包的一切缺陷,而且Acegi開發(fā)團(tuán)隊(duì)一直在改進(jìn)acls包。Acegi開發(fā)團(tuán)隊(duì)可能會(huì)在某個(gè)特定時(shí)刻將org.acegisecurity.acl包丟棄掉。
|
14.1.1 保護(hù)領(lǐng)域?qū)ο蟾攀?/h3>
Acegi于org.acegisecurity.acls.domain包內(nèi)置了表示ACL的如下Acl接口。通過這一接口,我們能夠獲得ACL持有的ACE集合、當(dāng)前ACL對應(yīng)的領(lǐng)域?qū)ο蟆⑦@一ACL的持有人(主人)、當(dāng)前ACL的父ACL等。
public interface Acl extends Serializable {
//獲得當(dāng)前ACL持有的ACE集合
public AccessControlEntry[] getEntries();
//當(dāng)前ACL對應(yīng)的領(lǐng)域?qū)ο?/p>
public ObjectIdentity getObjectIdentity();
//持有這一ACL的主人
public Sid getOwner();
//獲得當(dāng)前ACL的父ACL
public Acl getParentAcl();
//父ACL是否允許被當(dāng)前ACL繼承
public boolean isEntriesInheriting();
//用于ACL授權(quán)決定
public boolean isGranted(Permission[] permission, Sid[] sids,
boolean administrativeMode)
throws NotFoundException, UnloadedSidException;
//判斷當(dāng)前ACL是否已持有傳入的sids
public boolean isSidLoaded(Sid[] sids);
}
圖14-1展示了Acegi內(nèi)置的Acl繼承鏈,處于繼承鏈中的各個(gè)接口及類各有各的用途。比如,借助于MutableAcl能夠修改當(dāng)前的AclImpl實(shí)例,借助于AuditableAcl能夠完成ACL中ACE的審計(jì),借助于OwnershipAcl能夠修改當(dāng)前AclImpl實(shí)例的主人。

圖14-1 Acl繼承鏈
下面給出了Acegi內(nèi)置的用于表示ACE的AccessControlEntry策略接口。通常,Acl同AccessControlEntry具有1:N的關(guān)系,單個(gè)Acl持有若干個(gè)AccessControlEntry。
public interface AccessControlEntry {
//獲得其所在的ACL
public Acl getAcl();
//標(biāo)識(shí)當(dāng)前的ACE
public Serializable getId();
//表示的ACL(ACE)權(quán)限信息
public Permission getPermission();
//當(dāng)前ACL(ACE)權(quán)限信息的持有人,比如marissa用戶
public Sid getSid();
//當(dāng)前ACL(ACE)權(quán)限信息是否已經(jīng)授給了Sid
public boolean isGranting();
}
圖14-2展示了Acegi內(nèi)置的AccessControlEntry繼承鏈。

圖14-2 AccessControlEntry繼承鏈
在借助Acegi保護(hù)領(lǐng)域?qū)ο笃陂g,開發(fā)者幾乎不用同Acl和AccessControlEntry打交道,至少不用同AclImpl和AccessControlEntryImpl實(shí)現(xiàn)類交互。Acl和AccessControlEntry都使用到Sid接口,而Acl還使用到ObjectIdentity接口。Sid用于表示ACL授權(quán)過程中的授權(quán)對象,比如marissa用戶、ROLE_USER角色都可以成為Sid的表示對象。圖14-3展示了Acegi內(nèi)置的Sid繼承鏈。開發(fā)者將用戶名、Authentication對象傳入PrincipalSid構(gòu)建器便能夠構(gòu)建出PrincipalSid對象;同理,將角色、GrantedAuthority對象傳入GrantedAuthoritySid構(gòu)建器便能夠構(gòu)建出GrantedAuthoritySid對象。ObjectIdentity用于標(biāo)識(shí)單個(gè)領(lǐng)域?qū)ο螅@一對象的存在使得目標(biāo)企業(yè)應(yīng)用同Acegi間的耦合得到降低,ObjectIdentityImpl是Acegi內(nèi)置的唯一ObjectIdentity實(shí)現(xiàn)類。

圖14-3 Sid繼承鏈
Acegi提供的ACL子系統(tǒng)正是圍繞Acl、AccessControlEntry、Sid、ObjectIdentity展開的,這些對象存活于業(yè)務(wù)系統(tǒng)與RDBMS間。也正是這些接口的存在,我們才能夠?qū)cegi提供的ACL子系統(tǒng)作用到任何RDBMS中。也就是說,Acegi提供的領(lǐng)域?qū)ο笾С诌m合于所有的RDBMS、O/R Mapping技術(shù)。為了能夠從RDBMS裝載到相關(guān)對象,我們需要使用Acegi內(nèi)置的如下AclService接口。
//獲得ACL
public interface AclService {
//查找到parentIdentity的所有子ObjectIdentity,ACL管理工具經(jīng)常要使用到它
public ObjectIdentity[] findChildren(ObjectIdentity parentIdentity);
//通過ObjectIdentity獲得單個(gè)Acl對象
public Acl readAclById(ObjectIdentity object) throws NotFoundException;
//通過ObjectIdentity獲得僅適合于sids的單個(gè)Acl對象
public Acl readAclById(ObjectIdentity object, Sid[] sids)
throws NotFoundException;
//獲得ObjectIdentity[]對應(yīng)的Acl對象集合
public Map readAclsById(ObjectIdentity[] objects) throws NotFoundException;
//通過ObjectIdentity[]獲得僅適合于sids的Acl對象集合
public Map readAclsById(ObjectIdentity[] objects, Sid[] sids)
throws NotFoundException;
}
圖14-4展示了Acegi內(nèi)置的AclService繼承鏈,處于這一繼承鏈中的各個(gè)接口及實(shí)現(xiàn)類各有各的用途。比如,JdbcAclService用于實(shí)現(xiàn)AclService策略接口。

圖14-4 AclService繼承鏈
MutableAclService用于維護(hù)Acl實(shí)例,開發(fā)者經(jīng)常要同這一策略接口打交道,其定義如下。JdbcMutableAclService實(shí)現(xiàn)了MutableAclService。注意,開發(fā)者也可以提供O/R Mapping技術(shù)對應(yīng)的AclService實(shí)現(xiàn),比如Hibernate、JPA。Acegi僅僅實(shí)現(xiàn)了JDBC版本的AclService,開發(fā)者可以在自身的應(yīng)用中同時(shí)使用O/R Mapping技術(shù)和JDBC。
//維護(hù)Acl實(shí)例
public interface MutableAclService extends AclService {
//在RDBMS中創(chuàng)建不含ACE的ACL,即Acl對象
public MutableAcl createAcl(ObjectIdentity objectIdentity)
throws AlreadyExistsException;
//從RDBMS中刪除objectIdentity對應(yīng)的ACL
public void deleteAcl(ObjectIdentity objectIdentity, boolean deleteChildren)
throws ChildrenExistException;
//將現(xiàn)有的acl實(shí)例同步到RDBMS中
public MutableAcl updateAcl(MutableAcl acl) throws NotFoundException;
}
通過本節(jié)內(nèi)容,我們大致了解了Acegi提供的用于ACL子系統(tǒng)的各主要接口。本章后續(xù)內(nèi)容將圍繞這些接口展開論述。
14.1.3 ACL權(quán)限的定義
我們可以對領(lǐng)域?qū)ο筮M(jìn)行各種操作,比如新增、刪除、修改、瀏覽、管理等。Acegi將各種ACL權(quán)限信息建模在BasePermission對象中,相關(guān)的ACL權(quán)限信息摘錄如下。開發(fā)者經(jīng)常需要同READ、WRITE、CREATE、DELETE、ADMINISTRATION等ACL權(quán)限打交道,這些權(quán)限的含義非常容易理解。借助于FieldRetrievingFactoryBean,開發(fā)者能夠在DI容器中配置它們。
public static final Permission READ =
new BasePermission(1 << 0, 'R'); // 1
public static final Permission WRITE =
new BasePermission(1 << 1, 'W'); // 2
public static final Permission CREATE =
new BasePermission(1 << 2, 'C'); // 4
public static final Permission DELETE =
new BasePermission(1 << 3, 'D'); // 8
public static final Permission ADMINISTRATION =
new BasePermission(1 << 4, 'A'); // 16
圖14-7展示了Acegi內(nèi)置的Permission繼承鏈。BasePermission將基本的權(quán)限建模好了,而借助于CumulativePermission,開發(fā)者能夠建構(gòu)復(fù)合權(quán)限。比如,我們可以對READ、WRITE等權(quán)限進(jìn)行邏輯或運(yùn)算,進(jìn)而在RDBMS中存儲(chǔ)復(fù)合權(quán)限,從而簡化了ACL授權(quán)操作。

圖14-7 Permission繼承鏈
下面摘錄了ADMINISTRATION、READ、DELETE權(quán)限的定義示例,這些配置信息同樣摘自于applicationContext-common-authorization.xml配置文件。各個(gè)AclEntryVoter投票器和AbstractAclProvider子類需要引用到這些ACL權(quán)限定義。
<bean id="BasePermission.ADMINISTRATION"
class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField">
<value>org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION</value>
</property>
</bean>
<bean id="BasePermission.READ"
class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField">
<value>org.acegisecurity.acls.domain.BasePermission.READ</value>
</property>
</bean>
<bean id="BasePermission.DELETE"
class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField">
<value>org.acegisecurity.acls.domain.BasePermission.DELETE</value>
</property>
</bean>