`
lichdb
  • 浏览: 39287 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

acegi流程

阅读更多

很早就听说过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等表数据内容的编制了!!

分享到:
评论
1 楼 huzhiyong56 2011-11-04  
看着头都晕了。。。

相关推荐

    spring acegi 详细文档

    Acegi还提供了丰富的接口和类,允许开发者自定义认证和授权流程,例如创建自定义的`UserDetailsService`来从数据源加载用户信息,或者实现自定义的`AuthenticationProvider`以支持特定的认证逻辑。 尽管Spring ...

    Acegi使用.pdf

    Acegi安全系统由多个关键组件构成,每个组件负责处理安全流程的不同方面: 1. **Authentication对象**:封装了Principal(主体)、Credential(凭证)和授权信息,同时还可能包含客户发起认证请求时的额外信息,如...

    spring acegi 使用工程demo

    6. **jar.GIF 和 result.GIF**:这些可能是教程中的辅助图形,可能展示了配置步骤或者运行结果,帮助理解Acegi的工作流程。 总的来说,这个示例工程将展示如何在Spring环境中配置Acegi,创建用户、角色和权限,以及...

    acegi安全策略与CAS整合

    通过整合两者,可以简化用户登录流程,同时加强整体系统的安全性。 1.2 环境: 整合通常需要Java开发环境,Spring框架,以及支持的Web容器如Tomcat。同时,CAS服务器需要部署并配置好相应的认证策略。 1.3 下载...

    使用acegi控制用户权限实例

    - 一旦决定允许或拒绝访问,Acegi将相应地修改请求的流程。 在实际应用中,我们可能需要配置Acegi以适应我们的需求。这包括设置认证提供者、定义访问决策策略、以及为不同的资源分配权限。例如,我们可以通过XML...

    Acegi Security整合CAS实例

    Acegi Security与CAS的整合,不仅能够简化多应用间的用户登录流程,提升用户体验,还能增强系统的整体安全性。通过上述详细步骤的介绍,开发者可以了解到如何从零开始配置SSL环境、整合CAS Server与Acegi Security,...

    acegisecurity-1.0.7

    Acegi Security可以无缝集成Spring MVC、Spring JDBC、Spring ORM等组件,简化了开发流程。例如,它可以与Spring的Transaction Management一起工作,确保在不安全的操作发生时能回滚事务。 六、配置与使用 在实际...

    acegi+cas整合工程及说明1

    将acegi和cas的war包修改并整合测试,里面包含所需依赖包。经过分卷压缩一共3个文件.

    acegi学习整理合集

    "Acegi认证授权流程.txt"很可能是对Acegi中认证和授权流程的文本描述,包括用户请求的处理流程、权限检查、会话管理等。掌握这个流程对于调试和优化安全设置至关重要。 总的来说,这个合集提供了一个全面的学习路径...

    acegi-security-tiger-1.0.7.jar

    它允许开发者灵活地定义认证流程,以便适应不同应用的需求。 2. **授权(Authorization)**:框架支持基于角色的访问控制(RBAC),可以精细到方法级别,确保只有拥有特定权限的用户才能执行特定的操作。此外,它还...

    acegisecurity-1.0.7.zip_.acegisecuri_acegi security 1.0.7_acegi

    8. **异常处理**:在处理安全异常时,Acegi Security提供了统一的处理流程,如未授权、未认证等异常,可以被转换为特定的HTTP状态码,以便于前端进行处理。 综上所述,Acegi Security 1.0.7是一个强大的安全框架,...

    acegi-security-0.8.1.jar.zip

    用户可以通过自定义策略实现复杂的身份验证流程。 2. **授权**:框架支持角色和权限的基础架构,允许开发者为不同用户或角色分配不同的访问权限。它支持基于方法的安全性,这意味着你可以控制到方法级别的访问权限...

    acegi 入门培训教程

    Acegi的安全控制流程可以类比于乘飞机的过程:安检对应身份认证,登机对应资源访问控制,按号就座则对应领域对象的安全控制。通过这种方式,Acegi确保了只有经过认证的用户才能访问相应的资源,并且他们的操作权限...

    Spring源代码解析(十):Spring_Acegi框架授权的实现.doc

    `FilterSecurityInterceptor`的工作流程如下: 1. 拦截请求。 2. 如果请求未被检查过,则设置标记并进行安全检查。 3. 调用安全策略接口(如`AccessDecisionManager`)来决定是否允许访问。 4. 根据决策结果,要么...

    acegi学习

    首先,"Acegi安全系统介绍.doc"文档很可能是对Acegi框架的基础概述,它可能涵盖了Acegi的核心概念,如安全上下文、访问决策管理器、认证和授权流程。文档可能会讲解Acegi如何通过过滤器链与Spring MVC协同工作,拦截...

    acegi 安全框架实例

    测试类可能包含模拟用户登录、访问受保护资源以及异常处理等场景,以验证Acegi框架的正确配置和工作流程。 使用Acegi安全框架时,开发者需要在Spring配置文件中声明Acegi的相关组件,并定义安全策略。例如,可以...

    acegi集成CAS示例

    AceGI(Authentication and Credentials Engine for Grid Infrastructure)是一个用于企业级身份验证和授权的框架,它在Spring框架之上提供了一套...这不仅简化了用户的登录流程,同时也让安全管理变得更加集中和高效。

    Acegi开发指南.

    ### Acegi开发指南知识点详解 #### 一、Acegi简介 **Acegi**是一个基于Spring框架的安全性解决方案,专门设计用于Web应用的安全控制。Acegi的主要优势在于它提供了一种声明式的安全控制方式,允许开发者通过配置而...

    Spring的ACEGI的应用

    它演示了如何配置安全规则、定义用户角色、实现认证和授权流程。通过运行此示例,开发者可以更直观地理解Acegi Security的工作原理。 **8. 更新与Spring Security** 值得注意的是,Acegi Security在Spring 3.0版本...

Global site tag (gtag.js) - Google Analytics