ACEGI安全框架应用指南_第1页
ACEGI安全框架应用指南_第2页
ACEGI安全框架应用指南_第3页
ACEGI安全框架应用指南_第4页
ACEGI安全框架应用指南_第5页
已阅读5页,还剩40页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

45/45ACEGI安全框架应用指南级别:中级何平系统架构师,独立顾问,培训讲师.2005年12月26日文章来源于一次acegi的项目应用。因为业务需要与acegi框架缺省的应用方式有一定的区别,故在实际应用过程中尝试了对acegi的一定量的改造工作,从而具有一定的研究和学习价值。文章中关于Acegi的介绍收入了其他文章中的内容,已在参教资料中列出资料来源。内容大纲:

认识Acegi安全框架

安装并运行Acegi自带的范例

改造Acegi框架满足我们的业务要求

具体内容:

认识Acegi安全框架Acegi安全系统,是一个用于SpringFramework的安全框架,能够和目前流行的Web容器无缝集成.它使用了Spring的方式提供了安全和认证安全服务,包括使用BeanContext,拦截器和面向接口的编程方式.因此,Acegi安全系统能够轻松地适用于复杂的安全需求。安全涉及到两个不同的概念,认证和授权。前者是关于确认用户是否确实是他们所宣称的身份。授权则是关于确认用户是否有允许执行一个特定的操作。

在Acegi安全系统中,需要被认证的用户,系统或代理称为"Principal"。Acegi安全系统和其他的安全系统不同,它并没有角色和用户组的概念

关键组件Acegi安全系统包含以下七个关键的功能组件:lAuthentication对象,包含了Principal,Credential和Principal的授权信息.同时还可以包含关于发起认证请求的客户的其他信息,如IP地址。

2ContextHolder对象,使用ThreadLocal储存Authentication对象的地方。

3AuthenticationManager,用于认证ContextHolder中的Authentication对象。

4AccessDecissionManager,用于授权一个特定的操作。

5RunAsManager,当执行特定的操作时,用于选择性地替换Authentication对象.

6SecureObject拦截器,用于协调AuthenticationManager,AccessDecissionManager,RunAsManager和特定操作的执行.7ObjectDefinitionSource,包含了特定操作的授权定义.这七个关键的功能组件的关系如下图所示(图中灰色部分是关键组件):

安全管理对象Acegi安全系统目前支持两类安全管理对象.

第一类的安全管理对象管理AOPAlliance的MethodInvocation,开发人员可以用它来保护Spring容器中的业务对象。为了使Spring管理的Bean可以作为MethodInvocation来使用,Bean可以通过ProxyFactoryBean和BeanNameAutoProxyCreator来管理,就像在Spring的事务管理一样使用.

第二类是FilterInvocation。它用过滤器(Filter)来创建,并简单地包装了HTTP的ServletRequest,ServletResponse和FilterChain。FilterInvocation可以用来保护HTTP资源。通常,开发人员并不需要了解它的工作机制,因为他们只需要将Filter加入web.xml,Acegi安全系统就可以工作了.

安全配置参数每个安全管理对象都可以描述数量不限的各种安全认证请求。例如,MethodInvocation对象可以描述带有任意参数的任意方法的调用,而FilterInvocation可以描述任意的HTTPURL。

Acegi安全系统需要记录应用于每个认证请求的安全配置参数。例如,对于BankManager.getBalance(intaccountNumber)方法和BankManager.approveLoan(intapplicationNumber)方法,它们需要的认证请求的安全配置很不相同.

为了保存不同的认证请求的安全配置,需要使用配置参数。从实现的视角来看,配置参数使用ConfigAttribute接口来表示。Acegi安全系统提供了ConfigAttribute接口的一个实现,SecurityConfig,它把配置参数保存为一个字符串。

ConfigAttributeDefinition类是ConfigAttribute对象的一个简单的容器,它保存了和特定请求相关的ConfigAttribute的集合。

当安全拦截器收到一个安全认证请求时,需要决定应用哪一个配置参数。换句话说,它需要找出应用于这个请求的ConfigAttributeDefinition对象。这个查找的过程是由ObjectDefinitionSource接口来处理的。这个接口的主要方法是publicConfigAttributeDefinitiongetAttributes(Objectobject),其中Object参数是一个安全管理对象。因为安全管理对象包含有认证请求的详细信息,所以ObjectDefinitionSource接口的实现类可以从中获得所需的详细信息,以查找相关的ConfigAttributeDefiniton对象。

Acegi如何工作为了说明Acegi安全系统如何工作,我们设想一个使用Acegi的例子。通常,一个安全系统需要发挥作用,它必须完成以下的工作:

l首先,系统从客户端请求中获得Principal和Credential;

2然后系统认证Principal和Credential信息;

3如果认证通过,系统取出Principal的授权信息;

4接下来,客户端发起操作请求;

5系统根据预先配置的参数检查Principal对于该操作的授权;6如果授权检查通过则执行操作,否则拒绝。

那么,Acegi安全系统是如何完成这些工作的呢?首先,我们来看看Acegi安全系统的认证和授权的相关类图:

图中绿色部分是安全拦截器的抽象基类,它包含有两个管理类,AuthenticationManager和AccessDecisionManager,如图中灰色部分.AuthenticationManager用于认证ContextHolder中的Authentication对象(包含了Principal,Credential和Principal的授权信息);AccessDecissionManager则用于授权一个特定的操作。下面来看一个MethodSecurityInterceptor的例子:<beanid="bankManagerSecurity”

class=”net。sf.acegisecurity。intercept.method.MethodSecurityInterceptor”〉

〈propertyname="validateConfigAttributes">

〈value>true〈/value>

〈/property〉

〈propertyname=”authenticationManager">

<refbean="authenticationManager"/〉

</property〉

〈propertyname="accessDecisionManager">

<refbean="accessDecisionManager"/>

</property>

〈propertyname="objectDefinitionSource">

〈value>

net。sf.acegisecurity.context。BankManager.delete*=

ROLE_SUPERVISOR,RUN_AS_SERVERnet。sf。acegisecurity。context。BankManager.getBalance=

ROLE_TELLER,ROLE_SUPERVISOR,BANKSECURITY_CUSTOMER,RUN_

</value>

</property>

</bean>上面的配置文件中,MethodSecurityInterceptor是AbstractSecurityInterceptor的一个实现类。它包含了两个管理器,authenticationManager和accessDecisionManager。这两者的配置如下:

〈beanid="authenticationDao"class="net.sf.acegisecurity.providers。dao.jdbc.JdbcDaoImpl”>

<propertyname="dataSource">〈refbean=”dataSource”/>〈/property>

</bean〉

<beanid="daoAuthenticationProvider”

class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">

<propertyname="authenticationDao”><refbean=”authenticationDao"/〉</property>

</bean〉

<beanid=”authenticationManager"class="net.sf.acegisecurity.providers.ProviderManager”>

<propertyname="providers”>

<list〉<refbean="daoAuthenticationProvider"/></list>

〈/property〉

</bean>

〈beanid=”roleVoter"class=”net.sf.acegisecurity.vote.RoleVoter”/>

〈beanid="accessDecisionManager"class=”net.sf.acegisecurity.vote.AffirmativeBased"〉

<propertyname="allowIfAllAbstainDecisions"〉〈value〉false</value></property>

〈propertyname="decisionVoters">

<list〉<refbean="roleVoter"/></list>

</property〉

</bean>

准备工作做好了,现在我们来看看Acegi安全系统是如何实现认证和授权机制的。以使用HTTPBASIC认证的应用为例子,它包括下面的步骤:1。

用户登录系统,Acegi从acegisecurity.ui子系统的安全拦截器(如BasicProcessingFilter)中得到用户的登录信息(包括Principal和Credential)并放入Authentication对象,并保存在ContextHolder对象中;

2.安全拦截器将Authentication对象交给AuthenticationManager进行身份认证,如果认证通过,返回带有Principal授权信息的Authentication对象。此时ContextHolder对象的Authentication对象已拥有Principal的详细信息;

3.用户登录成功后,继续进行业务操作;4.安全拦截器(bankManagerSecurity)收到客户端操作请求后,将操作请求的数据包装成安全管理对象(FilterInvocation或MethodInvocation对象);5.然后,从配置文件(ObjectDefinitionSource)中读出相关的安全配置参数ConfigAttributeDefinition;6。接着,安全拦截器取出ContextHolder中的Authentication对象,把它传递给AuthenticationManager进行身份认证,并用返回值更新ContextHolder的Authentication对象;7。将Authentication对象,ConfigAttributeDefinition对象和安全管理对象(secureObject)交给AccessDecisionManager,检查Principal的操作授权;

8。如果授权检查通过则执行客户端请求的操作,否则拒绝;

AccessDecisionVoter注意上节的accessDecisionManager是一个AffirmativeBased类,它对于用户授权的投票策略,只要通过其中的一个授权投票检查,即可通过;它的allowIfAllAbstainDecisions属性值是false,意思是如果所有的授权投票是都是弃权,则通不过授权检查。Acegi安全系统包括了几个基于投票策略的AccessDecisionManager,上节的RoleVoter就是其中的一个投票策略实现,它是AccessDecisionVoter的一个子类。AccessDecisionVoter的具体实现类通过投票来进行授权决策,AccessDecisionManager则根据投票结果来决定是通过授权检查,还是抛出AccessDeniedException例外。

AccessDecisionVoter接口共有三个方法:publicintvote(Authenticationauthentication,Objectobject,ConfigAttributeDefinitionconfig);publicbooleansupports(ConfigAttributeattribute);publicbooleansupports(Classclazz);其中的vote方法返回int返回值,它们是AccessDecisionVoter的三个静态成员属性:ACCESS_ABSTAIN,,ACCESS_DENIED和ACCESS_GRANTED,它们分别是弃权,否决和赞成。Acegi安全系统中,使用投票策略的AccessDecisionManager共有三个具体实现类:AffirmativeBased、ConsensusBased和UnanimousBased.它们的投票策略是,AffirmativeBased类只需有一个投票赞成即可通过;ConsensusBased类需要大多数投票赞成即可通过;而UnanimousBased类需要所有的投票赞成才能通过。RoleVoter类是一个Acegi安全系统AccessDecisionVoter接口的实现.如果ConfigAttribute以ROLE_开头,RoleVoter则进行投票.如果GrantedAuthority的getAutority方法的String返回值匹配一个或多个以ROLE_开头的ConfigAttribute,则投票通过,否则不通过。如果没有以ROLE_开头的ConfigAttribute,RoleVoter则弃权。

小结到这里,我想各位对于Acegi安全框架的实现原理和运行机制已经有了较清楚的认识.下一步我们就理论联系实践来感觉一下Acegi给我们带来乐趣。

安装并运行acegi自带的范例为了让大家对acegi有一个感性的认识,下面我们一起来安装Acegi自带的demo,并运行它,亲身感觉Acegi都为我们带来了些什么。

需要的软件Acegi0。83版本注意,目前Acegi的发布版本还不是很稳定,如果大家要运行我后面提供的范列,最好是下载这个版本的。下载地址:

因为我们还需求分析它的源码,所以最好也下之

Tomcat5.5下载地址:

J2SE5。0下载地址:

安装范例1.

安装tomcat到合适的位置2.

解压acegi—security—0.8.3.zip,目录展开如下:

图中选中的文件就是我们将安装的demo.

3。

将acegi—security-sample-contacts—filter.war复制到tomcat/webapps目录下4。

启动tomcat5.

通过地址:访问demo界面如下:6.

打开上面的页面后,大家就可以亲身去体验Acegi为我们来了什么.

提示其实只要好好研究一下这个demo中对于Acegi的用法,基本上就可以掌握Acegi了.一起加油吧.

改造Acegi框架满足我们的业务要求

我们的Acegi的范例在前面介绍Acegi时,我们举例说明了Acegi是如何做到对业务对象的访问控制的。在更多的时候,对于Web应用程序还要控制页面的访问。而我们的业务要求就是这样的简单,根据不同的角色决定它能访问哪些页面和哪些对象的哪些方法.目前暂时不考虑具体角色的具体权限指派,关于这部分内容大家可以通过研究demo获得相应的知识。因为是举例说明Acegi的用法,现假设我们的web工程名为myacegi,其目录结构如下:

其中的secure目录下的文件就是我们希望受控制的页面.

src目录是我们的java源程序。

acegilogin.jsp是我们的登录界面.

logoff.jsp是我们的登出页面。

test.jsp页面中有我们对受控业务对象的受控方法的访问举例。

WEB-INF目录下的目录结构如下:

classes和lib目录就不再解释了

applicationContext-common-business.xml配置了例子中要使用的数据源

applicationContext-acegi-security.xml配置了例子中关于安全方面的内容

applicationContext—common-authorization。xml配置了例子中关于授权方面的内容

web.xml当然就是整个web应用的配置了。我们在这里先详细说明一下web.xml文件,其它的配置文件的内容将在后面的改造过程中不断深入web.xml文件内容如下:

〈?xmlversion="1.0"encoding=”UTF-8”?〉<!DOCTYPEweb-appPUBLIC’-//SunMicrosystems,Inc.//DTDWebApplication2.3//EN''’〉

<web-app>

〈display-name>myacegiexample〈/display—name>

〈context-param>

<param—name>contextConfigLocation〈/param—name>

<param—value>

/WEB—INF/applicationContext—acegi—security。xml

/WEB—INF/applicationContext—common—business。xml

/WEB—INF/applicationContext—common—authorization.xml

〈/param-value>

</context-param>

〈filter>

<filter—name〉AcegiFilterChainProxy</filter-name>

<filter-class〉

net.sf.acegisecurity。util.FilterToBeanProxy

</filter-class〉

〈init-param>

<param-name>targetClass</param-name>

〈param-value>

net。sf.acegisecurity。util。FilterChainProxy

〈/param—value>

</init—param〉

</filter〉

<filter-mapping>

<filter-name>AcegiFilterChainProxy〈/filter—name>

<url-pattern〉/*</url-pattern>

</filter-mapping〉

<listener>

<listener-class>

org.springframework.web.context。ContextLoaderListener

</listener-class>

〈/listener>

〈listener>

<listener-class>

net.sf。acegisecurity.ui.session.HttpSessionEventPublisher

</listener-class〉

〈/listener〉

〈welcome-〉

<welcome—</welcome-file〉

</welcome—〉

<taglib>

<taglib—uri>/spring</taglib-uri>

〈taglib-location>/WEB—INF/spring.tld</taglib-location>

</taglib>

</web-app>

在上面的配置中,我只说明与Acegi有直接关系的部分1。

定义了一个应用程序域的变量contextConfigLocation

〈context—param>

<param-name>contextConfigLocation〈/param—name>

〈param-value〉

/WEB—INF/applicationContext-acegi—security。xml

/WEB—INF/applicationContext-common—business.xml

/WEB—INF/applicationContext-common—authorization。xml

</param—value〉

〈/context—param>

这里列出了我们希望Spring框架(Acegi中已经自带的Spring)加载的关于Acegi的配置文件。

2.

定义了一个过滤器AcegiFilterChainProxy,〈filter>

<filter-name>AcegiFilterChainProxy〈/filter—name>

<filter—class>

net。sf。acegisecurity.util.FilterToBeanProxy

</filter-class>

<init-param>

<param—name>targetClass</param—name〉

<param-value>

net。sf.acegisecurity.util.FilterChainProxy

〈/param-value>

〈/init—param〉

</filter>

〈filter—mapping〉

<filter—name〉AcegiFilterChainProxy</filter—name>

<url—pattern〉/*</url—pattern>

〈/filter—mapping>这样的配置表时,当前web应用中的所用url的请求访问都会被这个过滤器捕获,也就是说,Acegi的页面控制其实和我们平时的开发一样,也是通过过滤器来实现的。

3.定义了两个监听器〈listener>

〈listener-class>

org.springframework.web.context.ContextLoaderListener

〈/listener-class〉

</listener>

<listener〉

<listener—class>

net。sf。acegisecurity.ui.session。HttpSessionEventPublisher

</listener—class>

</listener>

第一个是用来动态加载我们前面定义的应用程序域的变量contextConfigLocation中所列出的配置文件的,第二个是Acegi内部需求使用的事件发布器,我们不需求太多关心它的实现和用法,就这样放着吧.

总的来说,这个工程本身也是以demo程序作为样板来建立的。

想了解更多信息,建议下载范例代码。

改造schema通过Acegi的demo演示大家可以看到,它所提供的缺省用户验证办法是依据的用户名和登录密码,而对于授权访问方面是根据用户所付于的角色来进行判断的。但在我们的业务系统中,用户验证则有所不同。单位号、用户ID和登录密码三者放在一起才能验证一个用户。同样对于用户角色的查询办法也得变成以单位号加用户ID为条件。我们先来看看Acegi所提供的demo的表结构和表间关系.

CREATETABLEusers(

usernameVARCHAR(50)NOTNULLPRIMARYKEY,

passwordVARCHAR(50)NOTNULL,

enabledBITNOTNULL

);

CREATETABLEauthorities(

usernameVARCHAR(50)NOTNULL,

authorityVARCHAR(50)NOTNULL

);

CREATEUNIQUEINDEXix_auth_usernameONauthorities(username,authority);

CREATETABLEacl_object_identity(

idBIGINTGENERATEDBYDEFAULTASIDENTITY(STARTWITH0)NOTNULLPRIMARYKEY,

object_identityVARCHAR_IGNORECASE(250)NOTNULL,

parent_objectBIGINT,

acl_classVARCHAR_IGNORECASE(250)NOTNULL,

CONSTRAINTunique_object_identityUNIQUE(object_identity),

FOREIGNKEY(parent_object)REFERENCESacl_object_identity(id)

);

CREATETABLEacl_permission(

idBIGINTGENERATEDBYDEFAULTASIDENTITY(STARTWITH0)

NOTNULLPRIMARYKEY

acl_object_identityBIGINTNOTNULL,

recipientVARCHAR_IGNORECASE(100)NOTNULL,

maskINTEGERNOTNULL,

CONSTRAINTunique_recipientUNIQUE(acl_object_identity,recipient),

FOREIGNKEY(acl_object_identity)REFERENCESacl_object_identity(id)

);

注意:以上sql语句来源于Acegi网站,应用于hsql。网页地址:

通过上面的schema可以看出Acegi是如何管理用户和进行授权的。也就是说,如果要让其满足我们前面所提出的业务要求,第一步从schema这块就得进行改造。

我们业务上的实际要求很简单,还没有涉及到对象的方法访问的权限问题,只是想根据用户的角色来控制其页面和业务方法的调用。从而得到我们所需要的schema。

CREATETABLERS

(DWHvarchar(2)NOTNULL,

USER_IDvarchar(5)NOTNULL,

USER_NAMEvarchar(20),

ENABLEDvarchar(1)

,PRIMARYKEY(DWH,

XTBH,USER_ID));

CREATETABLEdbo.authorities

(DWHvarchar(2)NOTNULL,

USER_IDvarchar(5)NOTNULL,

authorityvarchar(50)NOTNULL

,PRIMARYKEY(DWH,

USER_ID,authority));

注意:以上sql语法为odbc格式。

到此,schema的改造完成,赶快到我们的数据库中实施它们吧。

改造登录页面我们要求,如果客户访问了我们声明要控制的页面,则将请求定位到登录页面,要求客户通过登录操作向系统表明自己的身份。下面就是我们在系统中使用的登录界面,它合demo自带的那个只有一点点区别,demo自带的那个只有用户名和登录密码两个字段,而我们的是单位号、用户ID和登录密码三个字段。页面最重要的源码如下:

<formaction=”<c:urlvalue=’j_acegi_security_check’/>"method="POST"〉

<table>

〈tr><td〉单位号:〈/td〉〈td><inputtype=’text'name='j_dwh'></td〉</tr>

<tr〉〈td>用户ID:</td><td〉〈inputtype='text'name='j_userid'〉</td>〈/tr>

〈tr〉<td>登录密码:</td><td〉<inputtype='password’name=’j_password’></td〉</tr>

<tr〉〈tdcolspan='2’〉〈inputname="submit"type=”submit”〉</td>〈/tr>

<tr〉〈tdcolspan='2'><=”reset"type="reset"></td></tr>

〈/table>

</form〉大家可以看出,这个页面其实没有什么特别之处,只是根据我们的业务要求修改表单的定义罢了。有一点要注意的是Action的值是j_acegi_security_check,这个值我们将在applicationContext-acegi—security.xml给出定义之所在,也就是说这里只是引用罢了。另外还有一点要注意的就是其中的三个字段值:j_dwh、j_userid、j_password在后面的Acegi的代码改造中要用到的

applicationContext—acegi—security。xml配置说明及其实现先看看整体内容:〈beans>

<!--========================FILTERCHAIN=======================--〉

<beanid="filterChainProxy"

class="net.sf。acegisecurity。util。FilterChainProxy”〉

〈propertyname=”filterInvocationDefinitionSource">

〈value>

CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON

PATTERN_TYPE_APACHE_ANT

/**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,basicProcessingFilter,anonymousProcessingFilter,securityEnforcementFilter

</value〉

〈/property〉

〈/bean>

〈!-—========================AUTHENTICATION=======================——>

<beanid="authenticationManager"

class="net.sf.acegisecurity.providers。ProviderManager”>

〈propertyname=”providers”>

<list>

〈reflocal=”daoAuthenticationProvider"/〉

<reflocal=”anonymousAuthenticationProvider"/〉

</list>

</property〉

〈/bean>

<beanid=”userDAO”class="erDAO"〉

<propertyname="dataSource">

〈refbean=”dataSource"/〉

〈/property>

〈/bean〉

〈beanid="cacheManager"

class="che.ehcache.EhCacheManagerFactoryBean”/>

〈beanid="userCacheBackend”

class="che。ehcache.EhCacheFactoryBean">

〈propertyname="cacheManager”>

〈reflocal=”cacheManager”/>

</property>

<propertyname=”cacheName">

<value>userCache〈/value>

〈/property>

〈/bean〉

<beanid="userCache”

class=”che.EhCacheBasedUserCache">

<propertyname="cache”>

〈reflocal="userCacheBackend"/>

</property>

</bean>

〈beanid=”daoAuthenticationProvider”

class="com。cqkyinfo.ydxt.acegi.dao。PasswordDaoAuthenticationProvider”〉

〈propertyname=”authenticationDao">

<reflocal="userDAO"/>

</property〉

<propertyname=”userCache">

<reflocal=”userCache”/>

</property>

〈/bean>

<!--AutomaticallyreceivesAuthenticationEventmessagesfromDaoAuthenticationProvider—->

〈beanid="loggerListener”

class="net.sf.acegisecurividers.dao。event。LoggerListener"/>

<beanid="basicProcessingFilter"

class="net.sf.acegisecurity.ui.basicauth.BasicProcessingFilter”>

<propertyname=”authenticationManager”>

〈reflocal="authenticationManager"/>

</property>

〈propertyname="authenticationEntryPoint">

〈reflocal=”basicProcessingFilterEntryPoint”/>

</property〉

〈/bean>

<beanid=”basicProcessingFilterEntryPoint"

class=”net。sf。acegisecurity。ui。basicauth.BasicProcessingFilterEntryPoint”〉

<propertyname="realmName">

<value〉ContactsRealm</value〉

</property>

</bean〉

<beanid=”anonymousProcessingFilter"

class="net.sf.acegisecurity.providers.anonymous.AnonymousProcessingFilter">

<propertyname="key">

〈value>foobar〈/value〉

〈/property>

<propertyname="userAttribute”>

<value>anonymousUser,ROLE_ANONYMOUS〈/value〉

</property>

</bean〉

<beanid=”anonymousAuthenticationProvider"

class=”net.sf.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider">

<propertyname="key">

<value〉foobar〈/value>

</property>

</bean>

<beanid=”httpSessionContextIntegrationFilter"

class="net.sf.acegisecurity。context.HttpSessionContextIntegrationFilter”>

〈propertyname="context"〉

<value>

net。sf。acegisecurity.context。security.SecureContextImpl

〈/value>

〈/property>

</bean>

<!——=====================HTTPREQUESTSECURITY====================—->

<beanid="securityEnforcementFilter"

class="net.sf.acegisecurity.intercept。web。SecurityEnforcementFilter”>

〈propertyname="filterSecurityInterceptor"〉

<reflocal=”filterInvocationInterceptor"/〉

〈/property>

〈propertyname="authenticationEntryPoint”〉

〈reflocal=”authenticationProcessingFilterEntryPoint"/>

</property〉

</bean>

〈beanid=”authenticationProcessingFilter”

class="com。cqkyinfo.ydxt.acegi.ui。webapp.AuthenticationProcessingFilter”〉

<propertyname="authenticationManager">

〈refbean="authenticationManager"/〉

〈/property>

〈propertyname="authenticationFailureUrl">

〈value>/acegilogin。jsp?login_error=1〈/value〉

〈/property>

〈propertyname="defaultTargetUrl”〉

〈value〉/〈/value〉

</property〉

<propertyname=”filterProcessesUrl”>

<value>/j_acegi_security_check</value>

</property〉

</bean〉

<beanid="authenticationProcessingFilterEntryPoint”

class="net。sf。acegisecurity。ui.webapp.AuthenticationProcessingFilterEntryPoint">

〈propertyname=”loginFormUrl">

〈value〉/acegilogin。jsp</value〉

</property>

<propertyname="forceHttps”>

<value〉false〈/value〉

</property〉

〈/bean>

〈beanid="httpRequestAccessDecisionManager"

class="net.sf.acegisecurity。vote.AffirmativeBased”>

〈propertyname="allowIfAllAbstainDecisions">

〈value>false</value〉

〈/property>

<propertyname="decisionVoters"〉

<list>

<refbean=”roleVoter"/>

</list〉

〈/property〉

</bean>

〈!——NotetheorderthatentriesareplacedagainsttheobjectDefinitionSourceiscritical.

TheFilterSecurityInterceptorwillworkfromthetopofthelistdowntotheFIRSTpatternthatmatchestherequestURL.

Accordingly,youshouldplaceMOSTSPECIFIC(iea/b/c/d.*)expressionsfirst,withLEASTSPECIFIC(iea/.*)expressionslast—->

<beanid="filterInvocationInterceptor”

class="net.sf.acegercept。web.FilterSecurityInterceptor”〉

〈propertyname="authenticationManager">

<refbean="authenticationManager”/〉

</property>

〈propertyname="accessDecisionManager”〉

〈reflocal="httpRequestAccessDecisionManager"/>

</property>

<propertyname=”objectDefinitionSource">

<value>

CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON

PATTERN_TYPE_APACHE_ANT

/index.jsp=ROLE_ANONYMOUS,ROLE_SUPERVISOR

/logoff.jsp=ROLE_ANONYMOUS,ROLE_SUPERVISOR

/acegilogin。jsp*=ROLE_ANONYMOUS,ROLE_SUPERVISOR

/**=ROLE_SUPERVISOR

</value>

〈/property>

</bean>

〈/beans>1.

FILTERCHAIN定义了beanfilterChainProxy,需求说明的部分是属性filterInvocationDefinitionSource的值/**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,basicProcessingFilter,anonymousProcessingFilter,securityEnforcementFilter它表时我们的过滤器将引用的一系列Acegi服务。2。

AUTHENTICATION定义了:a)

authenticationManager,也就是认证管理器,这个在介绍部分有说明。它的providers属性我们在这里指定了两个:

i.

一个是用于数据库认证的daoAuthenticationProviderbean

ii。

一个是用于匿名访问的anonymousAuthenticationProvider

b)

userDAO,这个bean是我们自己所改造的,实现了我们前面说定义的schema中users表和authorities表的访问.在demo中,这个对象叫做jdbcDaoImpl,而且是使用的Acegi的自己的实现,大家要注意一下。详情见源码。

packagecom.cqkyinfo。ydxt。acegi.dao;

importjava。sql。ResultSet;importjava.sql.SQLException;importjava.sql.Types;importjava.util。List;

importjavax.sql.DataSource;

importnet.sf。acegisecurity.BadCredentialsException;importnet。sf.acegisecurity.GrantedAuthority;importnet.sf。acegisecurity.GrantedAuthorityImpl;imporernameNotFoundException;

importorg。springframework。dao.DataAccessException;importorg.springframework。jdbc.core.SqlParameter;importorg。springframework。jdbc。core.support.JdbcDaoSupport;importorg.springframework.jdbc。object。MappingSqlQuery;

importcom.cqkyinfo.ydxt.acegi.IUser;imporer;importcom。cqkyinfo。ydxt.base.datavisitor。DTO;importcom.cqkyinfo.ydxt.exceptions.BusinessException;importcom。cqkyinfo。ydxt。xtgl.business。XTGLBLFacade;

publicclassUserDAOextendsJdbcDaoSupportimplements

PasswordAuthenticationDao{

publicstaticfinalStringDEF_AUTHORITIES_BY_DWH_AND_USERID_QUERY="SELECTdwh,user_id,authorityFROMauthoritiesWHEREdwh=?ANDuser_id=?";

privateMappingSqlQueryauthoritiesByDwhAndUseridMapping;

publicUserDAO(){

super();

}

publicIUserloadUserByDwhAndUseridAndPassword(Stringdwh,Stringuserid,

Stringpassword)throwsDataAccessException,

BadCredentialsException{

Useruser=null;

try{

DTOdto=XTGLBLFacade.getInstance().getUserManager().getLoginUser(

dwh,userid,password);

StringenabledStr=dto.getValue(”enabled”).toString();

booleanenabled=false;

if(enabledStr.equals("1”)){

enabled=true;

authoritiesByDwhAndUseridMapping=newAuthoritiesByDwhAndUseridMapping(

getDataSource());

ListdbAuths=authoritiesByDwhAndUseridMapping

.execute(newString[]{dwh,userid});

if(dbAuths.size()==0){

thrownewRuntimeException(”UserhasnoGrantedAuthority”);

}

GrantedAuthority[]arrayAuths={};

arrayAuths=(GrantedAuthority[])dbAuths。toArray(arrayAuths);

user=newUser(dwh,userid,password,enabled,true,true,true,

arrayAuths);

}catch(BusinessExceptione){

logger.error(e.getMessage());

}

returnuser;

}

/**

*Queryobjecttolookupauser’sauthorities.

*/

protectedclassAuthoritiesByDwhAndUseridMappingextendsMappingSqlQuery{

protectedAuthoritiesByDwhAndUseridMapping(DataSourceds){

super(ds,DEF_AUTHORITIES_BY_DWH_AND_USERID_QUERY);

declareParameter(newSqlParameter(Types.VARCHAR));

declareParameter(newSqlParameter(Types.VARCHAR));

compile();

protectedObjectmapRow(ResultSetrs,intrownum)throwsSQLException{

StringroleName=rs。getString(3);

GrantedAuthorityImplauthority=newGrantedAuthorityImpl(roleName);

returnauthority;

}

c)

cacheManager和userCacheBackend,这两大家一看就知道,我也是用的Acegi的实现.

d)

userCache是我们自己改造的,原因是demo中是以username为标识来区别被缓存的对象的,而我们是dwh+userid.

详情见源码。packagche;

imporche;imporcheException;importnet。sf.ehcache。Element;

impormons。logging.Log;impormons.logging.LogFactory;importorg.springframework.beans.factory.InitializingBean;importorg.springframework.dao.DataRetrievalFailureException;

impo.cqkyinfo.ydxt.acegi。IUser;

publicclassEhCacheBasedUserCacheimplementsUserCache,InitializingBean{

//~Staticfields/initializers=============================================

privatestaticfinalLoglogger=LogFactory.getLog(EhCacheBasedUserCache.class);

//~Instancefields========================================================

privateCachecache;

//~Methods====================

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论