很早就听说过acegi了,但是当初只是下载了,并且网上找了点资料稍微看了一下。因为没有用到,所以也没有实践。最近忽然要用到了,才发现acegi的配置可不像想像中的那么简单。在网上找10篇相关文章,其配置也会有10样,各个不同,让人无可奈何。
至于acegi到底是干嘛的,它的一些最基础的介绍我这就不废话了。最近因为要配置acegi,所以没办法,只好按照一个参考并且分析了一下acegi的部分源代码,总算对acegi稍微有所理解了。下面把acegi内部流程分析如下:
acegi原理:
1 web.xml中配置filter类 org.acegisecurity.util.FilterToBeanProxy,
并设置targetClass 参数为 org.acegisecurity.util.FilterChainProxy
或者设置targetBean参数值为spring中配置的beanname
2 FilterToBeanProxy初始化中,获取targetBean的值,通过spring获取是否存在
如不存在,则通过targetClass参数构造FilterChainProxy.class并通过spring
获取配置为该class的所有beanNames,并将第一个bean设置为delegate.
3 当符合pattern配置的web请求来临时,则直接将直接filter操作转给delegate即
FilterChainProxy类.
4 FilterChainProxy类也是Filter的实现类,它是通过spring注入方式生成的,
属性filterInvocationDefinitionSource的值在spring xml中配置.该值一般配置为字符串格式:
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/**=httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,
securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,
anonymousProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
但是filterInvocationDefinitionSource属性是一个类,以上字符串如何转化为类的实例的呢?
filterInvocationDefinitionSource extends ObjectDefinitionSource 类可以有多个
ConfigAttributeDefinition,每个ConfigAttributeDefinition又可以包含多个Filter.
5 FilterChainProxy的doFilter方法中,先根据请求生成一个FilterInvocation类,然后根据该
FilterInvocation类和4中配置的各种filter来得到处理当前请求的ConfigAttributeDefinition,
ConfigAttributeDefinition中存储了所有与当前请求有关的filters.接着根据所有的filters生成
一个VirtualFilterChain类,VirtualFilterChain中顺序调用每个filter的doFilter方法,最后再
执行Chain.doFilter方法即执行实际请求的servlet
6 以下说明各个filter的执行过程,如果配置了多个filter则filter会按照配置顺序执行.
6.1 HttpSessionContextIntegrationFilter 主要是在session中设置一个SecurityContext,而
SecurityContextHolder中也保存这个SecurityContext,而SecurityContext具备Authentication属性
而第一次new SecurityContext的时候,Authentication是没有内容的。当chain.doFilter执行完毕
后执行SecurityContextHolder.clearContext().
6.2 LogoutFilter 构造函数有两个参数: 1.退出后转向的url; 2.LogoutHandler
如果请求不以"/j_acegi_logout"结束,则chain.doFilter,否则从6.1中的SecurityContextHolder
中得到Authentication,并传入Authentication调用每一个LogoutHandler.logout方法。可以配置的
LogoutHandler有:
6.2.1 TokenBasedRememberMeServices.logout就是把cookie删掉
6.2.2 SecurityContextLogoutHandler.logout就是执行SecurityContextHolder.clearContext()
6.3 AuthenticationProcessingFilter 需要配置authenticationManager属性:
authenticationManager->ProviderManager.它需要配置providers属性,可配置如下三个:
6311 AnonymousAuthenticationProvider.authenticate(Authentication) 比较HashKey是否相同
6312 RememberMeAuthenticationProvider.authenticate(Authentication) 比较HashKey是否相同
以上两个如果HashKey不相同,则异常,相同则返回Authentication
6313 daoAuthenticationProvider-->DaoAuthenticationProvider:三个属性:
userDetailsService:必须设置项-->JdbcDaoImpl.通过username查询用户权限
userCache-->EhCacheBasedUserCache(cache:resourceCacheBackend,
cacheManager-->EhCacheManagerFactoryBean,resourceCache)
passwordEncoder-->Md5PasswordEncoder
AuthenticationProcessingFilter执行时先获得客户端传入的用户和密码,构造Authentication实例
UsernamePasswordAuthenticationToken,并通过ProviderManager验证是否正确。正确则转入成功页
面,否则错误页面。当配置了多个providers的时候,顺序验证,成功则不再调用下一个provider.
DaoAuthenticationProvider.authenticate方法流程是:
1 从参数authentication中获取userName
2 从userCache中根据userName获取userDetails
3 如果userDetails为空,则调用retrieveUser方法通过userDetailsService.loadUserByUsername
获取userDetails. loadUserByUsername方法里面做了什么呢?
a:根据usersByUsernameQuery查询语句查询出用户信息List,并获得第一个记录.是User类
b:根据authoritiesByUsernameQuery查询语句查询出用户的角色信息,保存在GrantedAuthorityImpl
类List中,GrantedAuthorityImpl是GrantedAuthority的实现类,getAuthority()方法将返回
role_name字段的值.然后将角色信息List转化成GrantedAuthority[]数组
c:构造new User[是UserDetails的实现类]返回。包含用户名、密码、角色GrantedAuthority[]数组。
4 额外的additionalAuthenticationChecks。校验密码等
5 用user置入userCache中
6 返回UsernamePasswordAuthenticationToken[Authentication的实现类],包括角色信息
7 这期间如果有异常,则抛出异常。因此最后返回了Authentication表明验明正身了。
6.4 SecurityContextHolderAwareRequestFilter 将servletRequest包装成SavedRequestAwareWrapper类,然后
再正常调用servlet
6.5 RememberMeProcessingFilter 通过rememberMeServices.autoLogin方法获得Authentication(cookie而来),
再调用authenticationManager.authenticate方法,SecurityContext中再保存该Authentication
6.6 anonymousProcessingFilter SecurityContext中保存一个AnonymousAuthenticationToken
6.7 ExceptionTranslationFilter 属性有:
AuthenticationProcessingFilterEntryPoint[具备属性:loginFormUrl,forceHttps],
AccessDeniedHandlerImpl[具备属性:errorPage]
该filter先调用chain.doFilter,并捕获该方法出现的异常。出现异常后,根据异常的
类型做如下处理:
如果是AuthenticationException或AccessDeniedException,则根据定义的loginFormUrl,将页面转向到该url
否则执行accessDeniedHandler.handle方法,转到errorPage页面
6.8 FilterSecurityInterceptor 该filter也是个重量级的filter,主要是个拦截器的作用。
该filter需要配置以下属性:
6.8.1 authenticationManager 同6.3.1 校验密码并获取角色信息
6.8.2 objectDefinitionSource
6.8.3 accessDecisionManager-->AffirmativeBased[具备两个属性:allowIfAllAbstainDecisions,decisionVoters]
而decisionVoters可以配置为
6821 RoleVoter 根据ROLE_来确定是否通过
6822 AuthenticatedVoter
FilterSecurityInterceptor.doFilter中做了什么呢?首先将requet,response,chian封装成FilterInvocation fi,
然后执行以下 a:beforeInvocation, b:fi.getChain().doFilter(...), c:afterInvocation 三个方法
A.beforeInvocation(FilterInvocation)方法返回值是InterceptorStatusToken,这个方法都做了什么呢?以下
1-6点说明了它的运行逻辑.
1 从6.8.2中配置的objectDefinitionSource,调用其getAttributes(fi)方法.getAttributes(fi)方法中
调用fi.getRequestUrl()得到url,然后调用objectDefinitionSource.lookupAttributes(url).
lookup方法就可以从数据库resource表中获取url对应的resource.
2 将1中查询出来的resource与url逐一比较,如果匹配,则获得相应GrantedAuthority[]即roles
3 将2中GrantedAuthority[]逐一getAuthority后根据','分隔拼凑成字符串authStr,并且new
ConfigAttributeEditor(),再调用ConfigAttributeEditor.setAsText(authStr)和
ConfigAttributeEditor.getValue(),将value强制转化成ConfigAttributeDefinition返回.
setAsText方法里面:new ConfigAttributeDefinition,再将authStr拆分成数组,逐一调用
addConfigAttribute方法将SecurityConfig(auth) add到ConfigAttributeDefinition中,再
setValue将ConfigAttributeDefinition设置为value.因此调用getValue的返回值可以强制转化为
ConfigAttributeDefinition类
4 通过SecurityContextHolder.getContext().getAuthentication()获取Authentication.此处根据配置
及Authentication.isAuthenticated()判断可能会再次调用 authenticationManager[6.8.1中配置]的
authenticate方法
5 调用accessDecisionManager.decide(authenticated, FilterInvocation, ConfigAttributeDefinition)。
下面分析一下AffirmativeBased这个decisionManager是如何decide的?
a: 对AffirmativeBased配置的每一个decisionVoter执行:调用voter.vote(Authentication,obj,
ConfigAttributeDefinition)获取是通过还是denny还是弃权
b: 如果denny的数量>0,则异常不通过,如果有一个通过的则decide方法完成返回
c: 根据AffirmativeBased的allowIfAllAbstainDecisions("如果全部弃权则通过")属性,
如果false,则抛出异常
RoleVoter.vote方法:从ConfigAttributeDefinition获取每一个ConfigAttribute.getAttribute(),
判断是否以"ROLE_"开头:
如是,检查Authentication中有没有与之匹配的,有则返回通过,无则返回denny
如不是,则返回弃权.
AuthenticatedVoter.vote方法:从ConfigAttributeDefinition获取每一个ConfigAttribute,调用
getAttribute(),判断是否是:
IS_AUTHENTICATED_FULLY:是则满足以下情况返回通过:
**.既不是RememberMeAuthentication也不是AnonymousAuthenticationToken的实例
IS_AUTHENTICATED_REMEMBERED:是则满足以下任一情况返回通过:
a*.Authentication是RememberMeAuthenticationToken的实例
b*.既不是RememberMeAuthentication也不是AnonymousAuthenticationToken的实例
IS_AUTHENTICATED_ANONYMOUSLY:是则满足以下任一情况返回通过:
a*.Authentication是AnonymousAuthenticationToken的实例
b*.既不是RememberMeAuthentication也不是AnonymousAuthenticationToken的实例
c*.Authentication是RememberMeAuthenticationToken的实例
以上3种情况的判断中,如果依然没有return通过,则只要有一个Attribute()与以上3个相同,则返回
denny,否则弃权.
6 根据FilterSecurityInterceptor是否配置了runAsManager,
如配置了,则设置SecurityContextHolder中的Authentication为runAsManager.buildRunAs方法返回值
并返回InterceptorStatusToken.contextHolderRefreshRequired=true
如没有配置则返回InterceptorStatusToken.contextHolderRefreshRequired=false
B.fi.getChain().doFilter servlet-api的doFilter方法
C.afterInvocation(InterceptorStatusToken,returnObject)方法都做了什么呢?以下1-6点说明了它的运行逻辑
1 如果InterceptorStatusToken==null,则返回returnObject
2 token.isContextHolderRefreshRequired(),是则SecurityContextHolder中的Authentication设置为
token.getAuthentication()
3 如果afterInvocationManager配置了,则调用afterInvocationManager.decide方法并返回decide的返回值.
注意:
TokenBasedRememberMeServices.key 与 RememberMeAuthenticationProvider.key 需要一致
AnonymousProcessingFilter.key 与 AnonymousAuthenticationProvider.key 需要一致
springside春天的的springside-2.0提供的bookstore例子中采用自定义的DBFilterInvocationDefinitionSource作为
FilterSecurityInterceptor.objectDefinitionSource属性.它继承自AbstractFilterInvocationDefinitionSource类
lookupAttributes(String url)方法被getAttributes(fi)调用.并且自定义了AcegiCacheManager和AcegiCacheManagerImpl
类实现缓存。AcegiCacheManagerImpl有几个方法需要说明一下:
1 initUserCache():获取所有用户以及用户角色,将角色转化为GrantedAuthority数组再构造UserDetails实例User置入
userCache
2 initResourceCache():获取所有resource以及对应角色,将角色转化为GrantedAuthority数组再构造ResourceDetails
实例Resource置入resourceCache.
以上的cache采用了ehcache.cache元素Element类都采用了res_string作为key.
lookupAttributes(url)中执行了如下过程:
1 acegiCacheManager.getUrlResStrings()获取所有resStr.即查询resource表中res_type="URL"的所有记录的res_string字段
2 比较所有res_string与url是否匹配,如果找到匹配项,立刻根据res_string获取对应的ResourceDetails接口即Resource实现类
3 调用Resource.getAuthorities()将数组以,分隔转化为字符串并通过ConfigAttributeEditor类转化为ConfigAttributeDefinition
返回给调用方.它又会被accessDecisionManager.decide方法作为参与调用,decide方法已经在前面介绍过了.
几个词汇: 对应数据库内容
Authentication:证明 用户表
Authority:权限 可能是role.每个角色的权限在acegi中描述为资源resource.而资源是通过url来区分的.
Credential:信任状 密码
Principal:负责人 用户名
因此重点就在于 role,resource等表数据内容的编制了!!
分享到:
相关推荐
Acegi 是一个在Java开发领域,特别是Spring框架中曾经广泛使用的安全组件,全称为Acegi Security。这个系统为Spring应用程序提供了全面的安全管理解决方案,包括身份验证、授权、会话管理以及安全事件处理等功能。...
Acegi Security是一个专门为Spring框架设计的权限控制框架,旨在为基于J2EE的企业级应用程序提供全面的安全服务。这个框架解决了J2EE规范中安全性配置不便于移植的问题,使得应用程序的安全设置能够在不同服务器环境...
【Acegi框架介绍 acegi安全与认证】 Acegi Security,现称为Spring Security,是一个强大的安全框架,主要用于基于Spring的企业级应用。它通过Spring的依赖注入(IoC)和面向切面编程(AOP)功能,提供了声明式的...
AceGI,全称为Acegi Security,是Java领域中一个用于Spring框架的安全组件,它提供了全面的身份验证、授权和会话管理功能。这个框架在早期的Spring版本中非常流行,为开发者构建安全的Web应用程序提供了强大的支持。...
Spring Acegi是一个安全框架,它为Spring应用提供了一套强大的身份验证和授权机制。这个框架在Spring Security(之前称为Spring Security)之前被广泛使用。在本文中,我们将深入探讨Spring Acegi的核心概念、功能和...
Acegi是Spring Security的前身,它是一个用于Java企业级应用的安全框架,提供了全面的身份验证、授权和会话管理功能。这个压缩包包含了Acegi的示例代码和一个学习资源,对于初学者来说是非常宝贵的资料。 首先,让...
被解剖的acegi配置文件. 博文链接:https://rmn190.iteye.com/blog/175041
Acegi是一个专门为SpringFramework应用提供安全机制的开放源代码项目,全称为Acegi Security System for Spring,当前版本为 0.8.3。它使用了Spring的方式提供了安全和认证安全服务,包括使用Bean Context,拦截器和...
Acegi安全系统,是一个用于Spring Framework的安全框架,能够和目前流行的Web容器无缝集成。它使用了Spring的方式提供了安全和认证安全服务,包括使用Bean Context,拦截器和面向接口的编程方式。因此,Acegi安全...
Spring Acegi是一个安全框架,它为Spring应用提供了全面的安全管理功能。这个"spring acegi 使用工程demo"显然是一个示例项目,旨在帮助开发者理解和实践如何在Spring应用中集成和使用Acegi安全框架。 首先,Acegi...
Acegi-Spring安全框架是一个专为基于Spring的企业应用设计的安全框架,现在被称为Spring Security。它提供了声明式的安全访问控制,允许开发者在Spring容器中配置安全相关的Bean,利用Spring的依赖注入(IoC)和面向...
Acegi安全系统,是一个用于Spring Framework的安全框架,能够和目前流行的Web容器无缝集成。它使用了Spring的方式提供了安全和认证安全服务,包括使用Bean Context,拦截器和面向接口的编程方式。因此,Acegi安全...
Spring Acegi权限控制是Spring框架中用于实现Web应用安全的一种解决方案。Acegi Security(现已被Spring Security替代)是一个功能强大的安全框架,它主要解决了认证(Authentication)和授权(Authorization)这两...
Acegi 是一个强大的 Java 安全框架,专用于系统安全编程,尤其在处理认证和授权方面表现出色。在本文中,我们将深入探讨 Acegi 的基本概念、如何设置以及它如何与 Spring 框架集成。 首先,让我们了解 Acegi 的核心...
### Acegi安全框架详解 #### 引言 Acegi安全框架是专为Spring框架设计的安全解决方案,它通过深度集成Spring的特性,提供了一套全面、灵活的安全管理方案。不同于传统的安全框架,Acegi采用了面向切面编程(AOP)...
acegi-security 1.0.2.jar
Acegi Security System for Spring Acegi Security是一款针对Spring框架的安全组件,它提供了全面的身份验证、授权和服务层安全功能。在深入探讨Acegi Security的源码之前,我们需要了解一些基本概念和背景知识。 ...
包含acegi-security-1.0.7.jar,acegi-security-1.0.7-sources.jar,acegi-security-cas-1.0.7.jar,acegi-security-cas-1.0.7-sources.jar,acegi-security-catalina-1.0.7.jar,acegi-security-catalina-1.0.7-...
acegi,spring的安全验证框架