资源信息:
code:
public Resource(String authResource, int
resType, GrantedAuthority[] authorities) {
// TODO
自动生成构造函数存根
if(authResource == null
||"".equals(authResource)){
throw new
IllegalArgumentException("can't put null or empty value to resource
string");
}
if(resType == 0){
throw new
IllegalArgumentException("can't put zero value to resource
type");
}
this.resString =
authResource;
this.resType = resType;
setAuthorities(authorities);
}
public GrantedAuthority[] getAuthorities()
{
return authorities;
}
protected void setAuthorities(GrantedAuthority[]
authorities) {
Assert.notNull(authorities,"can't
put a null GrantedAuthority arrays");
this.authorities =
authorities;
for (int i = 0; i <
authorities.length; i++) {
Assert.notNull(authorities,
"Granted Authority "+i+"is null" +
"||GrantedAuthorities[]
can't put any null elements");
}
}
getter and setter.......
|
资源缓存:
code:
public class ResourceCache {
private Cache cache;
/**
* 根据资源获取资源串
*/
public ResourceDetails
getAuthorityFromCache(String orgResource) {
// TODO 自动生成方法存根
Element element =null;
try {
element =
cache.get(orgResource);
} catch (CacheException e)
{
// TODO
自动生成 catch 块
throw new
DataRetrievalFailureException("Cache
failure:"+e.getMessage(),e);
}
if(element==null){
return
null;
}else{
return
(ResourceDetails) element.getValue();
}
}
/**
* 从Cache缓存移除资源权限
* @param orgResource
*/
public void removeAuthorityFromCache(String
orgResource) {
// TODO 自动生成方法存根
this.cache.remove(orgResource);
}
/**
* 将资源串放置Cache中
* @param rd
*/
public void putAuthorityInCache(ResourceDetails
rd) {
// TODO 自动生成方法存根
Element element = new
Element(rd.getResString(),rd);
this.cache.put(element);
}
public Cache getCache() {
return cache;
}
public void setCache(Cache cache) {
this.cache = cache;
}
public List getFunctions() {
// TODO 自动生成方法存根
return
getResourcesByType(Constants.RESOURCE_FUNCTION);
}
public List getComponents() {
// TODO 自动生成方法存根
return
getResourcesByType(Constants.RESOURCE_COMPONENT);
}
public List getUrlResStrings() {
// TODO 自动生成方法存根
return
getResourcesByType(Constants.RESOURCE_URL);
}
/**
* 通过资源类型获取资源
* @param i
* @return
*/
@SuppressWarnings("unchecked")
private List getResourcesByType(int type) {
// TODO 自动生成方法存根
List resources = null;
List resList = new
ArrayList();
try {
resources =
this.cache.getKeys();
} catch (IllegalStateException
e) {
// TODO
自动生成 catch 块
throw new
IllegalStateException("find source from cache
error:"+e.getMessage(),e);
} catch (CacheException e)
{
// TODO
自动生成 catch 块
throw new
UnsupportedOperationException("cache
error"+e.getMessage(),e);
}
for (Iterator iter =
resources.iterator(); iter.hasNext();) {
String
resString = (String) iter.next();
ResourceDetails
rd=getAuthorityFromCache(resString);
if(rd!=null
&& type ==rd.getResType()){
resList.add(resString);
}
}
return resList;
}
|
标识资源类别:
public class Constants {
public static final int
RESOURCE_URL = 1;
public static final int RESOURCE_FUNCTION =
2;
public static final int RESOURCE_COMPONENT =
3;
}
|
配置管理userCache和resourceCache
<!-- set userCahce
-->
<bean id="userCache"
class="org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache">
<property
name="cache">
<bean
class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property
name="cacheManager" ref="cacheManager"/>
<property
name="cacheName" value="userCache"/>
</bean>
</property>
</bean>
<!-- set resourceCache -->
<bean id="resourceCache"
class="com.runsa.components.acegi.resource.impl.ResourceCache"
autowire="byName">
<property
name="cache">
<bean
id="resourceCacheBackend"
class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property
name="cacheManager" ref="cacheManager"/>
<property
name="cacheName" value="resourceCache"/>
</bean>
</property>
</bean>
|
缓存管理器使用spring的ehcache
<!-- set cacheManager
-->
<bean id="cacheManager"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property
name="configLocation">
<!-- load
from classpath,or it can't load ehcache.xml -->
<value>classpath:ehcache.xml</value>
</property>
</bean> |
缓存的配置信息,在这里可以通过property设置,也可以通过配置文件实现
<ehcache>
<diskStore
path="java.io.tmpdir"/>
<!-- set default cache
-->
<defaultCache
maxElementsInMemory="30000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"/>
<!-- acegi user
cache-->
<cache name="userCache"
maxElementsInMemory="30000"
eternal="true"
overflowToDisk="true"/>
<!-- acegi resource
cache-->
<cache name="resourceCache"
maxElementsInMemory="30000"
eternal="true"
overflowToDisk="true"/>
</ehcache>
|
设置其最大缓存数量及过期时间,userCache与resourceCache设置永不过期eternal="true"
注意的问题:ehcache.xml需要通过classpath加载,否则加载不了.服务器启动时,
warning,ehcache.jar的ehcache_failsafe.xml load
failed....这样缓存的默认时间为:120s,缓存过期之后,就无法获取userCache和resourceCache的资源,将会认证无效.
下面实现方法级的权限设置.
<!-- * set methodServiceSecurity
-->
<bean id="methodServiceSecurity"
class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
<property
name="authenticationManager" ref="authenticationManager"/>
<property
name="accessDecisionManager"
ref="businessAccessDecisionManager"/>
<property
name="objectDefinitionSource"
ref="methodDefinitionSouce"/>
</bean>
<!-- set
businessAccessDicisionManager-->
<bean id="businessAccessDecisionManager"
class="org.acegisecurity.vote.AffirmativeBased">
<property
name="allowIfAllAbstainDecisions" value="false"/>
<property
name="decisionVoters">
<bean
class="org.acegisecurity.vote.RoleVoter">
<property
name="rolePrefix" value="ROLE_"/>
</bean>
</property>
</bean>
<!-- set methodDefinitionSouce for myself
implement with db -->
<bean id="methodDefinitionSouce"
class="com.runsa.components.acegi.inteceptor.method.DBMethodDefinitionSource">
<property
name="acegiCacheManager" ref="acegiCacheManager"/>
</bean> |
MethodSecurityInterceptor在方法调用前,将进行拦截认证.
objectDefinitionSource,定义的保护资源.通过配置文件加载的话
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
com.runsa.service.Users.find* = ROLE_ADMIN,ROLE_USER
com.runsa.service.Users.add* = ROLE_ADMIN
com.runsa.service.Users.update* = ROLE_ADMIN
com.runsa.service.Users.delete* = ROLE_ADMIN
<value>
这样就可以了,但为了动态实现,就从db中获取吧.
DBMethodDefinitionSource,自己实现MethodDefinitionSource.
public class
DBFilterInvocationDefinationSource extends
AbstractFilterInvocationDefinitionSource
{
private boolean
convertUrlToLowercaseBeforeComparison = false;
private boolean useAntPath = false;
private AcegiCacheManager
acegiCacheManager;
//ant path
private final PathMatcher pathMatcher=new
AntPathMatcher();
//perl5 path
private final PatternMatcher patternMatcher = new
Perl5Matcher();
/**
* 返回当前的url对应的role
*/
@SuppressWarnings("unchecked")
@Override
public ConfigAttributeDefinition
lookupAttributes(String url) {
// TODO 自动生成方法存根
acegiCacheManager.initResourceCache();
if(isUseAntPath()){
//第一个?标记索引
int
firstQuestionMarkIndex = url.lastIndexOf("?");
if(firstQuestionMarkIndex
!= -1){
url
= url.substring(0, firstQuestionMarkIndex);
}
}
//获取所有的url
List
urls=acegiCacheManager.getUrlResString();
//先顺序排列
Collections.sort(urls);
//然后倒叙排列
Collections.reverse(urls);
//将url在比较前都转换为小写
if(convertUrlToLowercaseBeforeComparison){
url
= url.toLowerCase();
}
//授予权限操作
GrantedAuthority
authorities []= new GrantedAuthority[0];
for (Iterator
iter = urls.iterator(); iter.hasNext();) {
String
resString = (String) iter.next();
boolean
matched = false;
//使用ant匹配url
if(isUseAntPath()){
matched
= pathMatcher.match(resString, url);
}else{
//perl5编译url
Pattern
compiledPattern;
Perl5Compiler
compiler=new Perl5Compiler();
try
{
compiledPattern
= compiler.compile(resString, Perl5Compiler.READ_ONLY_MASK);
}
catch (MalformedPatternException e) {
//
TODO 自动生成 catch 块
throw
new
IllegalArgumentException("资源字符串参数格式错误:"+resString,e);
}
matched
= patternMatcher.matches(url, compiledPattern);
}
//匹配正确
if(matched){
ResourceDetails
rd = acegiCacheManager.getAuthorityFromCache(resString);
authorities
= rd.getAuthorities();
break;
}
}
//配置res,role,权限大于0
if(authorities.length>0){
String
authoritiesStr = " ";
for
(int i = 0; i < authorities.length; i++) {
authoritiesStr
+= authorities[i].getAuthority()+",";
}
String
authStr =
authoritiesStr.substring(0,authoritiesStr.length()-1);
ConfigAttributeEditor
configAttrEditor = new
ConfigAttributeEditor();
configAttrEditor.setAsText(authStr.trim());
return
(ConfigAttributeDefinition) configAttrEditor.getValue();
}
return null;
}
public Iterator
getConfigAttributeDefinitions() {
// TODO 自动生成方法存根
return null;
}
getter and setter.......
|
好,那么现在要对你的方法进行拦截,就很方便了.
<bean id="newsService"
parent="txTemplate">
<property
name="proxyInterfaces"
value="com.runsa.service.NewsService"/>
<property name="target"
ref="newsServiceTarget"/>
<property
name="preInterceptors" ref="methodServiceSecurity"/>
</bean> |
在service中事务开始前进行安全调用拦截preInterceptors就OK.
最后一步,在users,roles,authorities改变的时候,更新userCache和resourceCache.一种方法就是,对service或者dao的改变users,roles,authorities
信息的时候,进行拦截,并更新相应的userCache和resourceCache,就可以达到动态实现了.但还有一种方法,就是利用hibernate的eventListener,对insert,update,delete,load进行监听操作.下边看我的实现:
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource"
ref="dataSource"/>
<property
name="eventListeners">
<map>
<entry
key="post-insert"><ref
bean="authenticationPostInsertListenerEvent"/></entry>
<entry
key="post-update"><ref
bean="authenticationPostUpdateListenerEvent"/></entry>
<entry
key="post-delete"><ref
bean="authenticationPostDeleteListenerEvent"/></entry>
</map>
</property>
<property
name="hibernateProperties">
..........
</property>
.........
</bean>
|
然后自己实现相应的监听器
<!-- set
authenticationPostUpdateListenerEvent
-->
<bean
id="authenticationPostUpdateListenerEvent"
class="com.runsa.components.acegi.cache.listener.AuthenticationPostUpdateListenerEvent">
<property
name="updateAcegiCache" ref="updateAcegiCache"/>
</bean>
.................................
|
....next page