Acegi安全pȝQ是一个用于Spring Framework的安全框Ӟ能够和目前流行的Web容器无缝集成。它使用了Spring的方式提供了安全和认证安全服务,包括使用Bean ContextQ拦截器和面向接口的~程方式。因此,Acegi安全pȝ能够L地适用于复杂的安全需求?br /> 安全涉及C个不同的概念Q认证和授权。前者是关于认用户是否实是他们所宣称的n份。授权则是关于确认用h否有允许执行一个特定的操作?br /> 在Acegi安全pȝ中,需要被认证的用Ppȝ或代理称?Principal"。Acegi安全pȝ和其他的安全pȝ不同Q它q没有角色和用户l的概念?br />Acegipȝ设计
关键lg
Acegi安全pȝ包含以下七个关键的功能组Ӟ
1 Authentication对象Q包含了PrincipalQCredential和Principal的授权信息。同时还可以包含关于发v认证h的客L其他信息Q如IP地址?br /> 2 ContextHolder对象Q用ThreadLocal储存Authentication对象的地斏V?br /> 3 AuthenticationManagerQ用于认证ContextHolder中的Authentication对象?br /> 4 AccessDecissionManagerQ用于授权一个特定的操作?br /> 5 RunAsManagerQ当执行特定的操作时Q用于选择性地替换Authentication对象?br /> 6 Secure Object拦截器,用于协调AuthenticationManagerQAccessDecissionManagerQRunAsManager和特定操作的执行?br /> 7 ObjectDefinitionSourceQ包含了特定操作的授权定义?br /> q七个关键的功能lg的关pd下图所C(图中灰色部分是关键组ӞQ?br />
安全理对象
Acegi安全pȝ目前支持两类安全理对象?br /> W一cȝ安全理对象理AOP Alliance的MethodInvocationQ开发h员可以用它来保护Spring容器中的业务对象。ؓ了Spring理的Bean可以作ؓMethodInvocation来用,Bean可以通过ProxyFactoryBean和BeanNameAutoProxyCreator来管理,像在Spring的事务管理一样用?br /> W二cLFilterInvocation。它用过滤器QFilterQ来创徏Qƈ单地包装了HTTP的ServletRequestQServletResponse和FilterChain。FilterInvocation可以用来保护HTTP资源。通常Q开发h员ƈ不需要了解它的工作机Ӟ因ؓ他们只需要将Filter加入web.xmlQAcegi安全pȝ可以工作了?br />
安全配置参数
每个安全理对象都可以描q数量不限的各种安全认证h。例如,MethodInvocation对象可以描述带有L参数的Q意方法的调用Q而FilterInvocation可以描述L的HTTP URL?br /> Acegi安全pȝ需要记录应用于每个认证h的安全配|参数。例如,对于BankManager.getBalanceQint accountNumberQ方法和BankManager.approveLoanQint applicationNumberQ方法,它们需要的认证h的安全配|很不相同?br /> Z保存不同的认证请求的安全配置Q需要用配|参数。从实现的视角来看,配置参数使用ConfigAttribute接口来表C。Acegi安全pȝ提供了ConfigAttribute接口的一个实玎ͼSecurityConfigQ它把配|参C存ؓ一个字W串?br /> ConfigAttributeDefinitioncLConfigAttribute对象的一个简单的容器Q它保存了和特定h相关的ConfigAttribute的集合?br /> 当安全拦截器收到一个安全认证请求时Q需要决定应用哪一个配|参数。换句话_它需要找出应用于q个h的ConfigAttributeDefinition对象。这个查扄q程是由ObjectDefinitionSource接口来处理的。这个接口的主要Ҏ是public ConfigAttributeDefinition getAttributes(Object object)Q其中Object参数是一个安全管理对象。因为安全管理对象包含有认证h的详l信息,所以ObjectDefinitionSource接口的实现类可以从中获得所需的详l信息,以查扄关的ConfigAttributeDefiniton对象?br />
Acegi如何工作
Z说明Acegi安全pȝ如何工作Q我们设想一个用Acegi的例子。通常Q一个安全系l需要发挥作用,它必d成以下的工作Q?br /> 1 首先Q系l从客户端请求中获得Principal和CredentialQ?br /> 2 然后pȝ认证Principal和Credential信息Q?br /> 3 如果认证通过Q系l取出Principal的授权信息;
4 接下来,客户端发h作请求;
5 pȝҎ预先配置的参数检查Principal对于该操作的授权Q?br /> 6 如果授权查通过则执行操作,否则拒绝?br /> 那么QAcegi安全pȝ是如何完成这些工作的呢?首先Q我们来看看Acegi安全pȝ的认证和授权的相关类Q?
安全拦截器的抽象基类Q它包含有两个管理类QAuthenticationManager和AccessDecisionManager。AuthenticationManager用于认证ContextHolder中的Authentication对象Q包含了PrincipalQCredential和Principal的授权信息)QAccessDecissionManager则用于授权一个特定的操作?br />
下面来看一个MethodSecurityInterceptor的例子:
<bean id="bankManagerSecurity"
class="net.sf.acegisecurity.intercept.method.MethodSecurityInterceptor">
<property name="validateConfigAttributes">
<value>true</value>
</property>
<property name="authenticationManager">
<ref bean="authenticationManager"/>
</property>
<property name="accessDecisionManager">
<ref bean="accessDecisionManager"/>
</property>
<property name="objectDefinitionSource">
<value>
net.sf.acegisecurity.context.BankManager.delete*=
ROLE_SUPERVISOR,RUN_AS_SERVER
net.sf.acegisecurity.context.BankManager.getBalance=
ROLE_TELLER,ROLE_SUPERVISOR,BANKSECURITY_CUSTOMER,RUN_
</value>
</property>
</bean>
上面的配|文件中QMethodSecurityInterceptor是AbstractSecurityInterceptor的一个实现类。它包含了两个管理器QauthenticationManager和accessDecisionManager。这两者的配置如下Q?br />
<bean id="authenticationDao" class="net.sf.acegisecurity.providers.dao.jdbc.JdbcDaoImpl">
<property name="dataSource"><ref bean="dataSource"/></property>
</bean>
<bean id="daoAuthenticationProvider"
class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="authenticationDao"><ref bean="authenticationDao"/></property>
</bean>
<bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager">
<property name="providers">
<list><ref bean="daoAuthenticationProvider"/></list>
</property>
</bean>
<bean id="roleVoter" class="net.sf.acegisecurity.vote.RoleVoter"/>
<bean id="accessDecisionManager" class="net.sf.acegisecurity.vote.AffirmativeBased">
<property name="allowIfAllAbstainDecisions"><value>false</value></property>
<property name="decisionVoters">
<list><ref bean="roleVoter"/></list>
</property>
</bean>
准备工作做好了,现在我们来看看Acegi安全pȝ是如何实现认证和授权机制的。以使用HTTP BASIC认证的应用ؓ例子Q它包括下面的步骤:
1. 用户dpȝQAcegi从acegisecurity.ui子系l的安全拦截器(如BasicProcessingFilterQ中得到用户的登录信息(包括Principal和CredentialQƈ攑օAuthentication对象Qƈ保存在ContextHolder对象中;
2. 安全拦截器将Authentication对象交给AuthenticationManagerq行w䆾认证Q如果认证通过Q返回带有Principal授权信息的Authentication对象。此时ContextHolder对象的Authentication对象已拥有Principal的详l信息;
3. 用户d成功后,l箋q行业务操作Q?br /> 4. 安全拦截器(bankManagerSecurityQ收到客L操作h后,操作请求的数据包装成安全管理对象(FilterInvocation或MethodInvocation对象Q;
5. 然后Q从配置文gQObjectDefinitionSourceQ中d相关的安全配|参数ConfigAttributeDefinitionQ?br /> 6. 接着Q安全拦截器取出ContextHolder中的Authentication对象Q把它传递给AuthenticationManagerq行w䆾认证Qƈ用返回值更新ContextHolder的Authentication对象Q?br /> 7. Authentication对象QConfigAttributeDefinition对象和安全管理对象(secure ObjectQ交lAccessDecisionManagerQ检查Principal的操作授权;
8. 如果授权查通过则执行客Lh的操作,否则拒绝Q?br />
AccessDecisionVoter
注意上节的accessDecisionManager是一个AffirmativeBasedc,它对于用h权的投票{略是,只要通过其中的一个授权投检查,卛_通过Q它的allowIfAllAbstainDecisions属性值是falseQ意思是如果所有的授权投票是都是弃权,则通不q授权检查?br /> Acegi安全pȝ包括了几个基于投策略的AccessDecisionManagerQ上节的RoleVoter是其中的一个投策略实玎ͼ它是AccessDecisionVoter的一个子cRAccessDecisionVoter的具体实现类通过投票来进行授权决{,AccessDecisionManager则根据投结果来军_是通过授权查,q是抛出AccessDeniedException例外?br /> AccessDecisionVoter接口共有三个ҎQ?br />public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config);
public boolean supports(ConfigAttribute attribute);
public boolean supports(Class clazz);
其中的voteҎq回intq回|它们是AccessDecisionVoter的三个静态成员属性:ACCESS_ABSTAIN,QACCESS_DENIED和ACCESS_GRANTEDQ它们分别是弃权Q否军_赞成?br /> Acegi安全pȝ中,使用投票{略的AccessDecisionManager共有三个具体实现c:AffirmativeBased、ConsensusBased和UnanimousBased。它们的投票{略是,AffirmativeBasedcd需有一个投赞成即可通过QConsensusBasedc需要大多数投票赞成卛_通过Q而UnanimousBasedc需要所有的投票赞成才能通过?br /> RoleVotercL一个Acegi安全pȝAccessDecisionVoter接口的实现。如果ConfigAttribute以ROLE_开_RoleVoter则进行投。如果GrantedAuthority的getAutorityҎ的Stringq回值匹配一个或多个以ROLE_开头的ConfigAttributeQ则投票通过Q否则不通过。如果没有以ROLE_开头的ConfigAttributeQRoleVoter则弃权?br />
安全拦截?/b>
拦截器如何工?br /> MethodInvocation拦截?br /> FilterInvocation拦截?br />认证
认证h
认证理?br /> Authentication Provider
授权
Access Decision Manager
Voting Decision Manager
授权理推荐
ContextHolder的用h?br /> 用户接口目标
HTTP会话认证
HTTP Basic认证
1、Log4j的概?br /> Log4j中有三个主要的组Ӟ它们分别是Logger、Appender和LayoutQLog4j 允许开发h员定义多个LoggerQ每个Logger拥有自己的名字,Logger之间通过名字来表明隶属关pR有一个LoggerUCؓRootQ它永远 存在Q且不能通过名字索或引用Q可以通过Logger.getRootLogger()Ҏ获得Q其它Logger通过 Logger.getLogger(String name)Ҏ?br /> Appender则是用来指明所有的log信息存放C么地方,Log4j中支持多UappenderQ如 console、files、GUI components、NT Event Loggers{,一个Logger可以拥有多个AppenderQ也是你既可以Log信息输出到屏q,同时存储C个文件中?br /> Layout的作用是控制Log信息的输出方式,也就是格式化输出的信息?br /> Log4j中将要输出的Log信息定义?U别,依次为DEBUG、INFO、WARN、ERROR和FATALQ当输出Ӟ只有U别高过配置中规定的 U别的信息才能真正的输出Q这样就很方便的来配|不同情况下要输出的内容Q而不需要更改代码,q点实在是方便啊?br />
2、Log4j的配|文?br /> 虽然可以不用配置文gQ而在E序中实现配|,但这U方法在如今的系l开发中昄是不可取的,能采用配|文件的地方一定一定要用配|文件。Log4j支持?U格式的配置文gQXML格式和Java的property格式Q本人更喜欢后者,首先看一个简单的例子吧,如下Q?br />
log4j.rootLogger=debug, stdout, R
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
# Pattern to output the caller's file name and line number.
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=example.log
log4j.appender.R.MaxFileSize=100KB
# Keep one backup file
log4j.appender.R.MaxBackupIndex=1
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n
首先Q是讄rootQ格式ؓ log4j.rootLogger=[level],appenderName, ...Q其中level是讄需要输Z息的U别Q后面是appender的输出的目的圎ͼappenderName是指定日志信息输出到哪个地斏V您可以同时指定多个输出目的地。配|日志信息输出目的地AppenderQ其语法?br /> log4j.appender.appenderName = fully.qualified.name.of.appender.class
log4j.appender.appenderName.option1 = value1
...
log4j.appender.appenderName.option = valueN
Log4j提供的appender有以下几U:
org.apache.log4j.ConsoleAppenderQ控制台Q?br /> org.apache.log4j.FileAppenderQ文Ӟ
org.apache.log4j.DailyRollingFileAppenderQ每天生一个日志文Ӟ
org.apache.log4j.RollingFileAppenderQ文件大到达指定尺寸的时候生新文gQ?br /> org.apache.log4j.WriterAppenderQ将日志信息以流格式发送到L指定的地方)
配置日志信息的格式(布局Q,其语法ؓQ?br /> log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class
log4j.appender.appenderName.layout.option1 = value1
....
log4j.appender.appenderName.layout.option = valueN
Log4j提供的layout有以下几U:
org.apache.log4j.HTMLLayoutQ以HTML表格形式布局Q,
org.apache.log4j.PatternLayoutQ可以灵zd指定布局模式Q,
org.apache.log4j.SimpleLayoutQ包含日志信息的U别和信息字W串Q,
org.apache.log4j.TTCCLayoutQ包含日志生的旉、线E、类别等{信息)
3、Log4j在程序中的?br /> 要在自己的类中用Log4jQ首先声明一个静态变量Logger logger=Logger.getLog("classname")Q在使用之前Q用PropertyConfigurator.configure ("配置文g")配置一下,现在可以用了Q用法如下:logger.debug("debug message")或者logger.info("info message")Q看下面一个小例子Q?br />
import com.foo.Bar;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
public class MyApp {
static Logger logger = Logger.getLogger(MyApp.class.getName());
public static void main(String[] args) {
// BasicConfigurator replaced with PropertyConfigurator.
PropertyConfigurator.configure(args[0]);
logger.info("Entering application.");
Bar bar = new Bar();
bar.doIt();
logger.info("Exiting application.");
}
}
[介]
对于一个典型的Web应用Q完善的认证和授权机制是必不可少的,在SpringFramework中,Juergen Hoeller提供的范例JPetStorel了一些这斚w的介l,但还q远不够QAcegi是一个专门ؓSpringFramework提供安全机制?目Q全UCؓAcegi Security System for SpringQ当前版本ؓ0.5.1Q就其目前提供的功能Q应该可以满绝大多数应用的需求?br />
本文的主要目的是希望能够说明如何在基于Spring构架的Web应用中用AcegiQ而不是详l介l其中的每个接口、每个类。注意,即对已l存在的Spring应用Q通过下面介绍的步骤,也可以马上n受到Acegi提供的认证和授权?br />
[基础工作]
在你的Web应用的lib中添加Acegi下蝲包中的acegi-security.jar
[web.xml]
实现认证和授权的最常用的方法是通过filterQAcegi亦是如此Q通常Acegi需要在web.xmld以下5个filter:
<filter>
<filter-name>Acegi Channel Processing Filter</filter-name>
<filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
<init-param>
<param-name>targetClass</param-name>
<param-value>net.sf.acegisecurity.securechannel.ChannelProcessingFilter</param-value>
</init-param>
</filter>
<filter>
<filter-name>Acegi Authentication Processing Filter</filter-name>
<filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
<init-param>
<param-name>targetClass</param-name>
<param-value>net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter</param-value>
</init-param>
</filter>
<filter>
<filter-name>Acegi HTTP BASIC Authorization Filter</filter-name>
<filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
<init-param>
<param-name>targetClass</param-name>
<param-value>net.sf.acegisecurity.ui.basicauth.BasicProcessingFilter</param-value>
</init-param>
</filter>
<filter>
<filter-name>Acegi Security System for Spring Auto Integration Filter</filter-name>
<filter-class>net.sf.acegisecurity.ui.AutoIntegrationFilter</filter-class>
</filter>
<filter>
<filter-name>Acegi HTTP Request Security Filter</filter-name>
<filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
<init-param>
<param-name>targetClass</param-name>
<param-value>net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter</param-value>
</init-param>
</filter>
最先引赯惑的是net.sf.acegisecurity.util.FilterToBeanProxyQAcegi自己的文档上解释是: “What FilterToBeanProxy does is delegate the Filter's methods through to a bean which is obtained from the
Spring application context. This enables the bean to benefit from the Spring application context lifecycle support and configuration flexibility.”,如希望深I的话,ȝ看源代码应该不难理解?br />
再下来就是添加filter-mapping了:
<filter-mapping>
<filter-name>Acegi Channel Processing Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>Acegi Authentication Processing Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>Acegi HTTP BASIC Authorization Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>Acegi Security System for Spring Auto Integration Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>Acegi HTTP Request Security Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
q里Q需要注意以下两点:
1) q几个filter的顺序是不能更改的,序不对无法正常工作;
2) 如果你的应用不需要安全传输,如httpsQ则?Acegi Channel Processing Filter"相关内容注释掉即可;
3) 如果你的应用不需要Spring提供的远E访问机Ӟ如Hessian and BurlapQ将"Acegi HTTP BASIC Authorization
Filter"相关内容注释掉即可?br />
[applicationContext.xml]
接下来就是要dapplicationContext.xml中的内容了,从刚才FilterToBeanFactory的解释可以看出,真正的filter?br />在Spring的applicationContext中管理:
1) 首先Q你的数据库中必d有保存用户名和密码的tableQAcegi要求table的schema必须如下Q?br />
CREATE TABLE users (
username VARCHAR(50) NOT NULL PRIMARY KEY,
password VARCHAR(50) NOT NULL,
enabled BIT NOT NULL
);
CREATE TABLE authorities (
username VARCHAR(50) NOT NULL,
authority VARCHAR(50) NOT NULL
);
CREATE UNIQUE INDEX ix_auth_username ON authorities ( username, authority );
ALTER TABLE authorities ADD CONSTRAINT fk_authorities_users foreign key (username) REFERENCES users
(username);
2) d讉K你的数据库的datasource和Acegi的jdbcDaoQ如下:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"><value>${jdbc.driverClassName}</value></property>
<property name="url"><value>${jdbc.url}</value></property>
<property name="username"><value>${jdbc.username}</value></property>
<property name="password"><value>${jdbc.password}</value></property>
</bean>
<bean id="jdbcDaoImpl" class="net.sf.acegisecurity.providers.dao.jdbc.JdbcDaoImpl">
<property name="dataSource"><ref bean="dataSource"/></property>
</bean>
3) dDaoAuthenticationProvider:
<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="authenticationDao"><ref bean="authenticationDao"/></property>
<property name="userCache"><ref bean="userCache"/></property>
</bean>
<bean id="userCache" class="net.sf.acegisecurity.providers.dao.cache.EhCacheBasedUserCache">
<property name="minutesToIdle"><value>5</value></property>
</bean>
如果你需要对密码加密Q则在daoAuthenticationProvider中加入:<property name="passwordEncoder"><ref
bean="passwordEncoder"/></property>QAcegi提供了几U加密方法,详细情况可看?br />net.sf.acegisecurity.providers.encoding
4) dauthenticationManager:
<bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref bean="daoAuthenticationProvider"/>
</list>
</property>
</bean>
5) daccessDecisionManager:
<bean id="accessDecisionManager" class="net.sf.acegisecurity.vote.AffirmativeBased">
<property name="allowIfAllAbstainDecisions">
<value>false</value>
</property>
<property name="decisionVoters">
<list><ref bean="roleVoter"/></list>
</property>
</bean>
<bean id="roleVoter" class="net.sf.acegisecurity.vote.RoleVoter"/>
6) dauthenticationProcessingFilterEntryPoint:
<bean id="authenticationProcessingFilterEntryPoint"
class="net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
<property name="loginFormUrl"><value>/acegilogin.jsp</value></property>
<property name="forceHttps"><value>false</value></property>
</bean>
其中acegilogin.jsp是登陆页面,一个最单的d面如下Q?br />
<%@ taglib prefix='c' uri='http://java.sun.com/jstl/core' %>
<%@ page import="net.sf.acegisecurity.ui.AbstractProcessingFilter" %>
<%@ page import="net.sf.acegisecurity.AuthenticationException" %>
<html>
<head>
<title>Login</title>
</head>
<body>
<h1>Login</h1>
<form action="<c:url value='j_acegi_security_check'/>" method="POST">
<table>
<tr><td>User:</td><td><input type='text' name='j_username'></td></tr>
<tr><td>Password:</td><td><input type='password' name='j_password'></td></tr>
<tr><td colspan='2'><input name="submit" type="submit"></td></tr>
<tr><td colspan='2'><input name="reset" type="reset"></td></tr>
</table>
</form>
</body>
</html>
7) dfilterInvocationInterceptor:
<bean id="filterInvocationInterceptor"
class="net.sf.acegisecurity.intercept.web.FilterSecurityInterceptor">
<property name="authenticationManager">
<ref bean="authenticationManager"/>
</property>
<property name="accessDecisionManager">
<ref bean="accessDecisionManager"/>
</property>
<property name="objectDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
\A/sec/administrator.*\Z=ROLE_SUPERVISOR
\A/sec/user.*\Z=ROLE_TELLER
</value>
</property>
</bean>
q里h意,要objectDefinitionSource中定义哪些页面需要权限访问,需要根据自q应用需求进行修改,我上面给?br />的定义的意思是q样的:
a. CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON意思是在比较请求\径时全部转换为小?br />b. \A/sec/administrator.*\Z=ROLE_SUPERVISOR意思是只有权限为ROLE_SUPERVISOR才能讉K/sec/administrator*的页?br />c. \A/sec/user.*\Z=ROLE_TELLER意思是只有权限为ROLE_TELLER的用h能访?sec/user*的页?br />
8) dsecurityEnforcementFilter:
<bean id="securityEnforcementFilter" class="net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter">
<property name="filterSecurityInterceptor">
<ref bean="filterInvocationInterceptor"/>
</property>
<property name="authenticationEntryPoint">
<ref bean="authenticationProcessingFilterEntryPoint"/>
</property>
</bean>
9) dauthenticationProcessingFilter:
<bean id="authenticationProcessingFilter"
class="net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
<property name="authenticationManager">
<ref bean="authenticationManager"/>
</property>
<property name="authenticationFailureUrl">
<value>/loginerror.jsp</value>
</property>
<property name="defaultTargetUrl">
<value>/</value>
</property>
<property name="filterProcessesUrl">
<value>/j_acegi_security_check</value>
</property>
</bean>
其中authenticationFailureUrl是认证失败的面?br />
10) 如果需要一些页面通过安全通道的话Q添加下面的配置:
<bean id="channelProcessingFilter" class="net.sf.acegisecurity.securechannel.ChannelProcessingFilter">
<property name="channelDecisionManager">
<ref bean="channelDecisionManager"/>
</property>
<property name="filterInvocationDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
\A/sec/administrator.*\Z=REQUIRES_SECURE_CHANNEL
\A/acegilogin.jsp.*\Z=REQUIRES_SECURE_CHANNEL
\A/j_acegi_security_check.*\Z=REQUIRES_SECURE_CHANNEL
\A.*\Z=REQUIRES_INSECURE_CHANNEL
</value>
</property>
</bean>
<bean id="channelDecisionManager" class="net.sf.acegisecurity.securechannel.ChannelDecisionManagerImpl">
<property name="channelProcessors">
<list>
<ref bean="secureChannelProcessor"/>
<ref bean="insecureChannelProcessor"/>
</list>
</property>
</bean>
<bean id="secureChannelProcessor" class="net.sf.acegisecurity.securechannel.SecureChannelProcessor"/>
<bean id="insecureChannelProcessor" class="net.sf.acegisecurity.securechannel.InsecureChannelProcessor"/>
[~少了什么?]
Acegi目前提供了两U?secure object"Q分别对面和方法进行安全认证管理,我这里介l的只是利用
FilterSecurityInterceptor对访问页面的权限控制Q除此之外,Acegiq提供了另外一个Interceptor―?br />MethodSecurityInterceptorQ它l合runAsManager可实现对对象中的Ҏ的权限控Ӟ使用Ҏ可参看Acegi自带的文?br />和contact范例?br />
[最后要说的]
本来以ؓ只是说明如何使用Acegi而已Q应该非常简单,但真正写h才发现想要条理清楚的理顺所有需要的beanq是?br />困难的,但愿我没有遗漏太多东西,如果我的文章有什么遗漏或错误的话Q还请参看Acegi自带的quick-start范例Q但?br />注意Q这个范例是不能直接拿来用的?br />分析和学习Spring中的jpetstore用户理
存在用户的系l,必然需要用Ld和认证,今天通过分析Spring中自带的jpetstore的例子来学习一下如何实现在Spring构架的系l中用户d?br />1、首先从注册用户开始,先看看jpetstore-servlet.xml中关于注册用Lbean定义Q从定义命名中就可以看出下面q段是注册用户的:
<bean name="/shop/newAccount.do" class="org.springframework.samples.jpetstore.web.spring.AccountFormController">
<property name="petStore"><ref bean="petStore"/></property>
<property name="validator"><ref bean="accountValidator"/></property>
<property name="successView"><value>index</value></property>
</bean>
1). formView呢?从AccountFormController的构造函C得到Q原来ؓEditAccountFormQ ?br />2). EditoAccountForm.jsp中显得非ؕQ其实没有多难理解的地方,最主要的是q个form既是d新用LQ又是编辑用户信息的Q所以显得有点ؕp糟的?br />2、添加好了新用户Q接下来看看如何dQ在jpetstore-servlet中发现这两个相关bean定义Q如下:
<bean name="/shop/signon.do" class="org.springframework.samples.jpetstore.web.spring.SignonController">
<property name="petStore"><ref bean="petStore"/></property>
</bean>
<bean name="/shop/signonForm.do" class="org.springframework.web.servlet.mvc.ParameterizableViewController">
<property name="viewName"><value>SignonForm</value></property>
</bean>
1). W二个bean是在q行时用戯入用户名和密码的formQ叫做SignonFormQ对于这?ParameterizableViewControllerQ用文档里的话说q是最单的ControllerQ其作用是在运行中指向 Controller而不是直接指向jsp文gQ仅此而已?br />2). SignonForm.jspQ里面就是一个简单的formQ其action是W一个beanQ即/shop/signon.doQ最需要注意的?signonForwardActionQ其主要作用是forward到需要输入用户名和密码的那个面上去Q这个变量哪里来的呢Q看看下面:
<bean id="secureHandlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="interceptors">
<list>
<ref bean="signonInterceptor"/>
</list>
</property>
<property name="urlMap">
<map>
<entry key="/shop/editAccount.do"><ref local="secure_editAccount"/></entry>
<entry key="/shop/listOrders.do"><ref local="secure_listOrders"/></entry>
<entry key="/shop/newOrder.do"><ref local="secure_newOrder"/></entry>
<entry key="/shop/viewOrder.do"><ref local="secure_viewOrder"/></entry>
</map>
</property>
</bean>
原来Q上面的signonInterceptor实现了preHandleQ因此在h上面的map面Ӟ首先要经q这个InterceptorQ看?SignonInterceptor的源码,原来在其中ؓsignon.jsp赋予一个signonForwardAction对象Q呵呵,ȝ明白了?br />3). 接下来去学习一下SignonControllerQ其M部分中可以看出,首先取出用户输入的username和passwordQ然后到数据库中验证 有没有这个用P如果没有q个用户Q返回各错误面Q如果成功,首先生成一个UserSession对象Q在request的session加入q个 userSessionQ注意这部分代码中给ZPagedListHolder分页的简单用方法,关于分页昄Q以后再学习吧?br />3、登录成功后Q就可以Ҏ不同的用戯施不同的行ؓ了,取得用户信息Q无非就是从session取出userSession卛_?br />

]]>