11.2 管理身份验证忽悠社区. [5 D p; D1 M+ O" Z; b
决定是否允许用户访问受保护资源的第一步是判断用户的身份。8 x7 g# H% g+ a# }# O& U
在大多数应用系统中,这意味着用户在一个登录屏上提供用户名和密码。用户名(或者主体)告诉应用系统用户声明自己是谁。为了确证用户的身份,用户需要同时提供一个密码(或凭证)。如果应用系统的安全机制确认密码是正确的,则系统假设用户的实际身份与他声明的身份相同。忽悠,忽悠社区,忽悠论坛.% h! g7 k( W7 T; w6 o
在Acegi中,是由认证管理器负责确定用户身份的。
7 t" G- f- W; f" j8 m; M$ H. p忽悠社区一个认证管理器由接口net.sf.acegisecurity.AuthenticationManager定义:- public interface AuthenticationManager
- {
- public Authentication authenticate(Authentication authentication) throws AuthenticationException;
- }
复制代码 认证管理器的authenticate()方法需要一个net.sf.acegisecurity.Authentication对象(其中可能只包括用户名和密码)作为参数,它会尝试验证用户身份。如果认证成功,authenticate()方法返回一个完整的Authentication对象,其中包括用户已被授予的权限(将由授权管理器使用)。如果认证失败,则它会抛出一个AuthenticationException。0 u* x' R. w6 H2 i
( e( f' N! w+ _1 b# C忽悠社区正如你所见到的,AuthenticationManager接口非常简单,而且你可以相当容易地实现自己的AuthenticationManager。但是Acegi提供了ProviderManager,作为AuthenticationManager的一个适用于大多数情形的实现。所以,我们不讨论开发自己的认证管理器,而是看一下如何使用ProviderManager。
% J9 n% ?' V2 V& h' s0 d V8 `/ P
, W. W& y. w# M, X2 z- c# Uwww.huuoo.com11.2.1 配置ProviderManager
" f" J, c7 X3 ?3 }0 n忽悠社区ProviderManager是认证管理器的一个实现,它将验证身份的责任委托给一个或多个认证提供者,如图11.2所示。 o2 T$ ?0 V$ V. j0 Y

图11.2 ProviderManager将身份验证的职责委托给一个或多个认证提供者 - d, j* J% i, M( j$ {" e
ProviderManager的思路是使你能够根据多个身份管理源来认证用户。它不是依靠自己实现身份验证,而是逐一遍历一个认证提供者的集合,直到某一个认证提供者能够成功地验证该用户的身份(或者已经尝试完了该集合中所有的认证提供者)。 你可以在Spring配置文件中按如下方式配置一个ProviderManager: - <bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager">
- <property name="providers">
- <list>
- <ref bean="daoAuthenticationProvider"/>
- <ref bean="passwordDaoProvider"/>
- </list>
- </property>
- </bean>
复制代码 www.huuoo.com, }( p- g! E5 \
通过providers属性可以为ProviderManager提供一个认证提供者的列表。通常你只需要一个认证提供者,但在某些情况下,提供由若干个认证提供者组成的列表是有用的。在这种情况下,如果一个认证提供者验证身份失败,可以尝试另一个认证提供者。一个认证提供者是由net.sf.acegisecurity.provider.AuthenticationProvider接口定义的。Spring提供了若干个AuthenticationProvider的有用实现,如下表所
: X$ o( _! O" ]6 c; b忽悠社区认证提供者 | 目的 | | net.sf.acegisecurity.adapters.AuthByAdapterProvider | 使用容器的适配器验证身份 | | net.sf.acegisecurity.providers.cas.CasAuthenticationProvider | 根据Yale中心认证服务验证身份 | | net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider | 从数据库中获取用户信息,包括用户名和密码 | | net.sf.acegisecurity.providers.jaas.JaasAuthenticationProvider | 从JAAS登录配置中获取用户信息 | | net.sf.acegisecurity.providers.dao.PasswordDaoAuthenticationProvider | 从数据库中获取用户信息,但让底层的数据源完成实际的身份验证 | | net.sf.acegisecurity.providers.rcp.RemoteAuthenticationProvider | 根据远程服务验证用户身份 | | net.sf.acegisecurity.runas.RunAsImplAuthenticationProvider | 针对身份已经被运行身份管理器替换的用户进行认证 | | net.sf.acegisecurity.providers. TestingAuthenticationProvider | 用于单元测试。自动认为一个TestingAuthenticationToken是有效的。不应用于生产环境。 | 忽悠,忽悠社区,忽悠论坛.) d; Y' x( ~. g
你可以认为一个AuthenticationProvider是一个下属的AuthenticationManager。事实上,AuthenticationProvider接口也有一个authenticate()方法,该方法的签名与AuthenticationManager的authenticate()方法完全一样。忽悠社区是综合性社区网站,将最新、最快、最专业的资讯、新闻,图片,视频奉献给所有爱好者。6 p7 D( u8 I3 e$ p9 {
+ c2 {$ r; u4 l
在本节中,我们关注表11.1中列出的三个最常用的认证提供者。首先从使用DaoAuthenticationProvider进行简单的基于数据库验证身份开始。
( y7 O3 J& Q5 w9 i, A5 w/ }忽悠社区忽悠社区是综合性社区网站,将最新、最快、最专业的资讯、新闻,图片,视频奉献给所有爱好者。9 O8 T9 h9 S1 I+ q: E; {/ r5 n
11.2.2 根据数据库验证身份: X; h5 U. w( I3 F
大多数应用系统将包括用户名和密码在内的用户信息保存在数据库中。如果这和你的情况相符,则你会发现Acegi提供的以下两个认证提供者是有用的:
6 G) }# t- P$ s0 z" Y% x忽悠社区是综合性社区网站,将最新、最快、最专业的资讯、新闻,图片,视频奉献给所有爱好者。DaoAuthenticationProvider
( Z. G& y/ \4 m- W' m忽悠社区PasswordDaoAuthenticationProvider
0 g: m$ J0 \) X0 b- w. F' J www.huuoo.com+ t7 p* n$ S: N: E
这两个认证提供者都能使你通过将用户的主体和密码与数据库记录进行比较来验证用户身份。忽悠社区是综合性社区网站,将最新、最快、最专业的资讯、新闻,图片,视频奉献给所有爱好者。5 E) O* c6 y" g+ m
两者的不同之处在于真正的身份验证是在哪里进行的。 O) N/ w9 H) E: d5 n
DaoAuthenticationProvider使用Dao来获取用户名和密码,并使用它们来验证用户身份。9 v3 j5 q. i5 N9 H8 Q4 Z
而PasswordDaoAuthenticationProvider将身份验证的责任推给Dao自己完成。
) w$ d5 Z# \$ b忽悠社区是综合性社区网站,将最新、最快、最专业的资讯、新闻,图片,视频奉献给所有爱好者。这是一个重要的区别,等到我们在11.2.3节中讨论PasswordDaoAuthenticationProvider时,这个区别会变得更清楚。
9 l' \' v% E3 o* J! Q k8 \忽悠社区
6 S* n; \/ h3 j忽悠社区在本节中,我们看一下如何使用DaoAuthenticationProvider根据保存在某个数据源(通常是关系数据库)中的用户信息进行简单的身份验证。忽悠社区是综合性社区网站,将最新、最快、最专业的资讯、新闻,图片,视频奉献给所有爱好者。) p8 x4 l* J" C3 `* `; G5 d! J
在下一节中你将看到如何使用PasswordDaoAuthenticationProvider根据一个LDAP(轻型目录访问协议)用户库进行身份验证。
0 e0 {- l' Z- V( C, Q' N" Qwww.huuoo.com
$ B% o; i: w& b% {9 l1 B5 }, Z一个DaoAuthenticationProvider是一个简单的认证提供者,它使用DAO来从数据库中获取用户信息(包括用户的密码)。忽悠,忽悠社区,忽悠论坛.. P8 g1 {3 w9 T0 @
取得了用户名和密码之后,DaoAuthenticationProvider通过比较从数据库中获取的用户名和密码以及来自认证管理器的通过Authentication对象中传入的主体和凭证完成身份验证(见图11.3)。如果用户名和密码与主体和凭证匹配,则用户通过身份验证,同时返回给认证管理器一个已完全填充的Authentication对象。否则会抛出一个AuthenticationException,表明身份验证失败。
' y ^0 n& P* @% H1 e8 l
2 \1 x0 N6 T, i$ g! ?, Z
; \6 r+ M! p3 g7 R* i忽悠社区是综合性社区网站,将最新、最快、最专业的资讯、新闻,图片,视频奉献给所有爱好者。配置一个DaoAuthenticationProvider再简单不过了。下一段XML摘要显示了如何声明一个DaoAuthenticationProvider
) f( R }; v: g忽悠社区Bean,并且装配上它所依赖的DAO。- <bean id="authenticationProvider" class="net.sf.acegisecurity. providers.dao.DaoAuthenticationProvider">
- <property name="authenticationDao">
- <ref bean="authenticationDao"/>
- </property>
- </bean>
复制代码 属性authenticationDao指定了一个用于从数据库中获取用户信息的Bean。这个属性期望赋予一个net.sf.acegisecurity.providers.dao.AuthenticationDao的实例。接下来的问题就是该如何配置authenticationDaoBean了。
* x/ B! W. @, I" F ~' I; `忽悠社区7 `3 r. i" Y- y& C+ w+ u' i
Acegi提供了两个可供选择的AuthenticationDao的实例:InMemoryDaoImpl和JdbcDaoImpl。我们首先配置一个InMemoryDaoImpl作为authenticationDao Bean的实例,然后再使用更实用的JdbcDaoImpl替换它。www.huuoo.com: f0 }$ s6 D( Y
忽悠社区9 h1 ]. \1 ^6 e$ ]
使用内存DAO
$ `' f& C5 d& E5 y2 `+ Z: Q忽悠社区尽管假定AuthenticationDao对象总是通过查询关系数据库获取用户信息是一种自然的想法,事实情形却不必总是如此。如果你的应用系统的身份验证需求是微不足道的,或者是为了开发期间方便起见,也许更简单的做法是在Spring配置文件中直接配置你的用户信息。
$ m; c8 C; \7 N7 J8 E忽悠,忽悠社区,忽悠论坛.为此,Acegi提供了InMemoryDaoImpl,一个从Spring配置文件中获取用户信息的AuthenticationDao。你能够在Spring配置文件中通过以下方式配置一个InMemoryDaoImpl:- <bean id="authenticationDao" class="net.sf.acegisecurity. providers.dao.memory.InMemoryDaoImpl">
- <property name="userMap">
- <value>
- palmerd=4moreyears,ROLE_PRESIDENT
- bauerj=ineedsleep,ROLE_FIELD_OPS,ROLE_DIRECTOR
- myersn=traitor,disabled,ROLE_CENTRAL_OPS
- </value>
- </property>
- </bean>
复制代码 属性userMap使用一个net.sf.acegisecurity.providers.dao.memory.UserMap对象来定义一组用户名、密码和权限。幸运的是,当装配一个InMemoryDaoImpl时,你不必为配置一个UserMap实例而操心,因为Acegi提供了一个属性编辑器,它能够帮你把一个字符串转化为一个UserMap对象。
- ^" @/ J5 d- }4 F1 u+ h4 \userMap字符串的每一行都是一个名字―值对,其中名字是用户名,值是一个由逗号分隔的列表,它以用户名密码开头,后面跟着一个或多个赋予该用户的权限的名字(可以将权限看作角色)。
7 Z; M0 ?4 G% p+ \2 @& v忽悠,忽悠社区,忽悠论坛., a: B) O) ~$ z( n
Myersn=traitor, disabled,ROLE_CENTRAL_OPS
1 J4 Z8 n' h& ` T- a" ~www.huuoo.com
$ h5 j- |" Y! b5 j# u7 Y% ?忽悠社区以上的authenticationDao声明中定义了三个用户:palmerd、bauerj和myersn。这三个用户的密码分别是4moreyears、ineedsleep、和traitor。用户palmerd被定义为拥有权限ROLE_PRESIDENT,bauerj被赋予权限ROLE_FIELD_OPS和ROLE_DIRECTOR,并且用户myersn被给予ROLE_CENTRAL_OPS授权。
' C# b- G) N3 l忽悠,忽悠社区,忽悠论坛.
8 h4 p! |2 K$ T+ ~: h7 r忽悠社区是综合性社区网站,将最新、最快、最专业的资讯、新闻,图片,视频奉献给所有爱好者。注意用户myersn的密码后面有disabled这个单词。这是一个特殊的标志,表明该用户已被禁用。忽悠社区是综合性社区网站,将最新、最快、最专业的资讯、新闻,图片,视频奉献给所有爱好者。1 a& U3 i7 }' g9 g3 B- `
InMemoryDaoImpl有明显的局限性。最主要的一点是,对安全性进行管理时要求你重新编辑Spring的配置文件并且重新部署应用。虽然在开发环境下这是可以接受的(而且可能还是有帮助的),但对于生产用途而言这种做法就太笨拙了。因此,我们强烈反对在生产环境下使用InMemoryDaoImpl,而是应该考虑使用JdbcDaoImpl。
7 i$ m/ V5 y$ L6 i) Q' D忽悠,忽悠社区,忽悠论坛.忽悠社区, l" J' @- `- r7 J
声明一个JDBC DAOwww.huuoo.com$ }! c( C9 X0 r1 R. p
JdbcDaoImpl是一个简单而灵活的认证DAO。以它最简单的形式,只需要一个javax.sql.DataSource对象的引用,可以通过以下方式在Spring配置文件中进行声明:- <bean id="authenticationDao" class="net.sf.acegisecurity.providers.dao.jdbc.JdbcDaoImpl">
- <property name="dataSource">
- <ref bean="dataSource"/>
- </property>
- </bean>
复制代码 JdbcDaoImpl假设你在数据库中已经建立了某些用于存放用户信息的表。忽悠社区是综合性社区网站,将最新、最快、最专业的资讯、新闻,图片,视频奉献给所有爱好者。 G+ L% O" L$ r( z# z* I7 t, I7 |. X; E
特别地,它假设有一张“Users”表和一张“授权”表,如图11.4所示。# _5 K8 D- n! U% C9 `

当JdbcDaoImpl查找用户信息时,它会使用“SELECT username,password,enabled FROM users WHERE ; G0 w; J" b3 @: {- r
username = ?”作为查询语句。类似地,当查找授权时,它会使用“SELECT username,authority FROM authorities 忽悠,忽悠社区,忽悠论坛.9 y+ O- R7 R0 L5 s$ r
WHERE username = ?”。 忽悠社区4 C# p% U7 f7 K
尽管JdbcDaoImpl假定的表结构非常直接,它们很可能与你已经为应用系统建立的表结构不一致。比如,在Spring培训应用中,Student表保存用户名(在login列中)和密码。是否这意味着你无法在Spring培训应用中使用JdbcDaoImpl来验证学生的身份?忽悠,忽悠社区,忽悠论坛. ~% N* [- ~8 k& F5 t5 w
当然不是。但你必须通过设置usersByUserNameQuery属性告诉JdbcDaoImpl如何找到用户信息。下面是对authenticationDao Bean的调整使它更适合Spring培训应用: - <bean id="authenticationDao" class="net.sf.acegisecurity.providers.dao.jdbc.JdbcDaoImpl">
- <property name="dataSource">
- <ref bean="dataSource"/>
- </property>
- <property name="usersByUserNameQuery">
- <value>SELECT login, password FROM student WHERE login=?</value>
- </property>
- </bean>
复制代码现在JdbcDaoImpl知道如何在Student表中查找用户的认证信息了。 但是,还有一件事遗漏了。Student表中没有标志表明用户是使能的还是禁用的。事实上,我们一直假设所有的学生都是使能的。但我们如何告诉JdbcDaoImpl做同样的假设? 忽悠,忽悠社区,忽悠论坛." [7 \+ h9 j) |
JdbcDaoImpl还有一个usersByUserNameMapping属性,它引用一个MappingSqlQuery实例。 正如你回忆起第4章中所介绍的,MappingSqlQuery的mapRow()方法将一个ResultSet中的字段映射为一个领域对象。 对于JdbcDaoImpl,提供给usersByUserNameMapping属性的MappingSqlQuery对象要求能够将一个ResultSet(通过执行用户查询获得)转换为一个net.sf.acegisecurity.UserDetails对象。www.huuoo.com: f) m q5 m8 U7 t( Q8 A/ W
UsersByUserNameMapping(程序清单11.1)显示了一个MappingSqlQuery的实现,它适合将学生用户表的一个查询结果转换为一个UserDetails对象。它从ResultSet中抽取出username和password,但总是设置enabled属性为true。 程序清单11.1 将学生查询的结果映射为一个UserDetails对象 - public class UsersByUsernameMapping extends MappingSqlQuery
- {
- protected UsersByUsernameMapping(DataSource dataSource)
- {
- super(dataSource, usersByUsernameQuery);
- declareParameter(new SqlParameter(Types.VARCHAR));
- compile();
- }
-
- protected Object mapRow(ResultSet rs, int rownum) throws SQLException
- {
- String username = rs.getString(1);
- String password = rs.getString(2);
- UserDetails user = new User(username, password, true,
- new GrantedAuthority[]
- {new GrantedAuthorityImpl("HOLDER")});
- return user;
- }
- }
复制代码剩下惟一需要做的事就是声明一个UsersByUsernameMapping
/ j) h* o/ C/ w* @8 L忽悠社区Bean,并将它装配到usersByUserNameMapping属性中。以下的authenticationDao
9 V+ k) a- w: R/ sBean的声明将一个内部Bean装配至usersByUserNameMapping属性中,从而可以应用新的用户映射: - <bean id="authenticationDao" class="net.sf.acegisecurity.providers.dao.jdbc.JdbcDaoImpl">
- <property name="dataSource">
- <ref bean="dataSource"/>
- </property>
- <property name="usersByUserNameQuery">
- <value>SELECT login, password FROM student WHERE login=?</value>
- </property>
- <property name="usersByUserNameMapping">
- <bean class= "com.springinaction.training.security.UsersByUsernameMapping"/>
- </property>
- </bean>
复制代码你也能改变JdbcDaoImpl查询用户权限的方式。与属性usersByUserNameQuery和usersByUserNameMapping定义JdbcDaoImpl如何查询用户认证信息相同,属性authoritiesByUserNameQuery和authoritiesByUserNameMapping告诉JdbcDaoImpl如何查询用户的权限:例如,你可以使用以下代码从user_privileges表中查询已授予一个用户的权限。 - <bean id="authenticationDao" class="net.sf.acegisecurity.providers.dao.jdbc.JdbcDaoImpl">
- <property name="dataSource">
- <ref bean="dataSource"/>
- </property>
- <property name="usersByUserNameQuery">
- <value>SELECT login, password FROM student WHERE login=?</value>
- </property>
- <property name="usersByUserNameMapping">
- <bean class="com.springinaction.training.security.UsersByUsernameMapping"/>
- </property>
- <property name="authoritiesByUserNameQuery">
- <value>SELECT login, privilege FROM user_privileges where login=?</value>
- </property>
- </bean>
复制代码你也可以将属性authoritiesByUserNameMapping设置成一个定制的MappingSqlQuery对象,从而可以定制权限查询的结果如何映射为一个net.sf.acegisecurity.GrantedAuthority对象。但是,由于默认的MappingSqlQuery对上面给出的查询来说已经足矣,我们就不再画蛇添足了。
1 ?) h# L, G) u: O# x- O8 p忽悠社区是综合性社区网站,将最新、最快、最专业的资讯、新闻,图片,视频奉献给所有爱好者。使用加密的密码
8 e i7 `$ ?1 q* r8 y. X0 b忽悠社区是综合性社区网站,将最新、最快、最专业的资讯、新闻,图片,视频奉献给所有爱好者。默认地,DaoAuthenticationProvider假设用户的密码是以明文方式(未加密的方式)存储的。但在与从数据库中取出的密码进行比较之前,可以使用一个密码编码器加密用户输入的明文密码。Acegi提供了三个密码编码器:
" Y, e. ?! x, z: q忽悠社区PlaintextPasswordEncoder(默认)――不对密码进行编码,直接返回未经改变的密码;, h6 o, V0 L* f" m
Md5PasswordEncoder ――对密码进行消息摘要(MD5)编码;
; `2 K1 F* q7 n忽悠,忽悠社区,忽悠论坛.ShaPasswordEncoder ――对密码进行安全哈希算法(SHA)编码。 你可以通过设置DaoAuthenticationProvider的passwordEncoder属性改变它的密码编码器。例如,要使用MD5编码可以用以下代码: - <property name="passwordEncoder">
- <bean class= "net.sf.acegisecurity.providers.encoding.Md5PasswordEncoder"/>
- </property>
复制代码你也需要设置编码器的种子源(salt source)。一个种子源为编码提供种子(salt),或者称编码的密钥。Acegi提供两个种子源:
+ l- Z+ N R6 s- x/ @* YReflectionSaltSource――使用用户的User对象中某个指定的属性来获取种子; SystemWideSaltSource――对系统中所有用户使用相同的种子。
& Y) i# S7 D! q: u/ LSystemWideSaltSource适用于大多数情形。以下一段XML将一个SystemWideSaltSource装配到DaoAuthenticationProvider的saltSource属性中: - <property name="saltSource">
- <bean class= "net.sf.acegisecurity.providers.dao.SystemWideSaltSource">
- <property name="systemWideSalt">
- <value>123XYZ</value>
- </property>
- </bean>
- </property>
复制代码ReflectionSaltSource使用用户对象的某个特定属性作为用户密码的编码种子。由于这意味着每个用户的密码都会以不同的方式编码,因此更安全。若要装配一个ReflectionSaltSource,可以通过如下方式将它装配到saltSource属性中: - <property name="saltSource">
- <bean class="net.sf.acegisecurity.providers.dao.ReflectionSaltSource">
- <property name="userPropertyToUse">
- <value>userName</value>
- </property>
- </bean>
- </property>
复制代码
; }$ C/ [3 s$ n2 `9 ]. S在这里,用户的userName属性被用作种子来加密用户的密码。要特别重视的是必须保证种子是静态的,永远不会改变;否则,一旦种子改变,就再也不可能对用户身份进行验证了。
! P6 n! J; t0 u( q' [' E忽悠,忽悠社区,忽悠论坛.缓存用户信息
1 I4 n' H Z" z" @' G. \忽悠社区每次当请求一个受保护的资源时,认证管理器就被调用以获取用户的安全信息。但如果获取用户信息涉及到查询数据库,每次都查询相同的数据可能在性能上表现得很糟糕。注意到用户信息不会频繁改变,也许更好的做法是在第一次查询时缓存用户信息,并在后续的查询中直接从缓存中获取用户信息。
G( }, Q. M9 g/ X, X+ ~忽悠,忽悠社区,忽悠论坛.DaoAuthenticationProvider通过net.sf.acegisecurity.providers.dao.UserCache接口的实现类支持对用户信息进行缓存。
- public interface UserCache {
- public UserDetails getUserFromCache(String username);
- public void putUserInCache(UserDetails user);
- public void removeUserFromCache(String username);
- }
复制代码顾名思义,接口UserCache中方法提供了向缓存中放入、取得和删除用户明细信息的功能。写一个你自己的UserCache实现类是相当简单的。然而,在你考虑开发自己的UserCache实现类之前,应该首先考虑Acegi提供的两个方便的UserCache实现类: net.sf.acegisecurity.providers.dao.cache.NullUserCache7 C. f+ L& D4 s, ^" L
net.sf.acegisecurity.providers.dao.cache.EhCacheBasedUserCache NullUserCache事实上不进行任何缓存。任何时候调用它的getUserFromCache方法,得到的返回值都是null。这是DaoAuthenticationProvider使用的默认UserCache实现。
; T, U, l" K5 ^* o4 @5 b忽悠社区EhCacheBasedUserCache是一个更实用的缓存实现。类如其名,它是基于开源项目ehcache实现的。ehcache是一个简单快速的针对Java的缓存解决方案,同时也是Hibernate默认的和推荐的缓存方案。(关于ehcache的更多信息,请访问ehcache的网站 http://ehcache.sourceforge.net) 忽悠社区" Y# s& B9 \& P
在DaoAuthenticationProvider中使用ehcache是很简单的,只需要简单地声明一个EhCacheBasedUserCase Bean即可: - <bean id="userCache" class="net.sf.acegisecurity.providers.dao.cache.EhCacheBasedUserCache">
- <property name="minutesToIdle">15</property>
- </bean>
复制代码属性minutesToIdle告诉缓存器一条用户信息在没有访问的情况下应该在缓存中保存多久。这里,我们设定在15分钟的非活动期后删除该条用户信息。 忽悠社区是综合性社区网站,将最新、最快、最专业的资讯、新闻,图片,视频奉献给所有爱好者。) b7 d$ I0 [; w4 ?" @+ H( {
声明了userCache Bean之后,下面惟一要做的事就是把它装配到DaoAuthenticationProvider的userCache属性中: - <bean id="authenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
- <property name="userCache">
- <ref bean="userCache"/>
- </property>
- </bean>
复制代码 |