Spring Security(07)——缓存UserDetails
? ? ? ?Spring Security提供了一个实现了可以缓存UserDetails的UserDetailsService实现类,CachingUserDetailsService。该类的构造接收一个用于真正加载UserDetails的UserDetailsService实现类。当需要加载UserDetails时,其首先会从缓存中获取,如果缓存中没有对应的UserDetails存在,则使用持有的UserDetailsService实现类进行加载,然后将加载后的结果存放在缓存中。UserDetails与缓存的交互是通过UserCache接口来实现的。CachingUserDetailsService默认拥有UserCache的一个空实现引用,NullUserCache。以下是CachingUserDetailsService的类定义。
public?class CachingUserDetailsService implements UserDetailsService {
??? private UserCache userCache = new NullUserCache();
??? private?final UserDetailsService delegate;
?
??? CachingUserDetailsService(UserDetailsService delegate) {
??????? this.delegate = delegate;
??? }
?
??? public UserCache getUserCache() {
??????? return?userCache;
??? }
?
??? public?void setUserCache(UserCache userCache) {
??????? this.userCache = userCache;
??? }
?
??? public UserDetails loadUserByUsername(String username) {
??????? UserDetails user = userCache.getUserFromCache(username);
?
??????? if (user == null) {
??????????? user = delegate.loadUserByUsername(username);
??????? }
?
??????? Assert.notNull(user, "UserDetailsService " + delegate + " returned null for username " + username + ". " +
??????????????? "This is an interface contract violation");
?
??????? userCache.putUserInCache(user);
?
??????? return user;
??? }
}
?????? 我们可以看到当缓存中不存在对应的UserDetails时将使用引用的UserDetailsService类型的delegate进行加载。加载后再把它存放到Cache中并进行返回。除了NullUserCache之外,Spring Security还为我们提供了一个基于Ehcache的UserCache实现类,EhCacheBasedUserCache,其源码如下所示。
public?class EhCacheBasedUserCache implements UserCache, InitializingBean {
?
??? private?static?final Log logger = LogFactory.getLog(EhCacheBasedUserCache.class);
?
??? private Ehcache cache;
?
??? public?void afterPropertiesSet() throws Exception {
??????? Assert.notNull(cache, "cache mandatory");
??? }
?
??? public Ehcache getCache() {
??????? returncache;
??? }
?
??? public UserDetails getUserFromCache(String username) {
??????? Element element = cache.get(username);
??????? if (logger.isDebugEnabled()) {
??????????? logger.debug("Cache hit: " + (element != null) + "; username: " + username);
??????? }
??????? if (element == null) {
??????????? returnnull;
??????? } else {
??????????? return (UserDetails) element.getValue();
??????? }
??? }
?
??? public?void putUserInCache(UserDetails user) {
??????? Element element = new Element(user.getUsername(), user);
??????? if (logger.isDebugEnabled()) {
??????????? logger.debug("Cache put: " + element.getKey());
??????? }
??????? cache.put(element);
??? }
?
??? public?void removeUserFromCache(UserDetails user) {
??????? if (logger.isDebugEnabled()) {
??????????? logger.debug("Cache remove: " + user.getUsername());
??????? }
????? ??this.removeUserFromCache(user.getUsername());
??? }
?
??? public?void removeUserFromCache(String username) {
??????? cache.remove(username);
??? }
?
??? public?void setCache(Ehcache cache) {
??????? this.cache = cache;
??? }
}
?
?????? 从上述源码我们可以看到EhCacheBasedUserCache所引用的Ehcache是空的,所以,当我们需要对UserDetails进行缓存时,我们只需要定义一个Ehcache实例,然后把它注入给EhCacheBasedUserCache就可以了。接下来我们来看一下定义一个支持缓存UserDetails的CachingUserDetailsService的示例。
?? <security:authentication-manager alias="authenticationManager">
????? <!-- 使用可以缓存UserDetails的CachingUserDetailsService -->
????? <security:authentication-provider
???????? user-service-ref="cachingUserDetailsService" />
?? </security:authentication-manager>
?? <!-- 可以缓存UserDetails的UserDetailsService -->
?? <bean id="cachingUserDetailsService" class="org.springframework.security.config.authentication.CachingUserDetailsService">
????? <!-- 真正加载UserDetails的UserDetailsService -->
????? <constructor-arg ref="userDetailsService"/>
????? <!-- 缓存UserDetails的UserCache -->
????? <property name="userCache">
???????? <bean class="org.springframework.security.core.userdetails.cache.EhCacheBasedUserCache">
??????????? <!-- 用于真正缓存的Ehcache对象 -->
??????????? <property name="cache" ref="ehcache4UserDetails"/>
???????? </bean>
????? </property>
?? </bean>
?? <!-- 将使用默认的CacheManager创建一个名为ehcache4UserDetails的Ehcache对象 -->
?? <bean id="ehcache4UserDetails" class="org.springframework.cache.ehcache.EhCacheFactoryBean"/>
?? <!-- 从数据库加载UserDetails的UserDetailsService -->
?? <bean id="userDetailsService"
????? class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
????? <property name="dataSource" ref="dataSource" />
?? </bean>
?
?????? 在上面的配置中,我们通过EhcacheFactoryBean定义的Ehcache bean对象采用的是默认配置,其将使用默认的CacheManager,即直接通过CacheManager.getInstance()获取当前已经存在的CacheManager对象,如不存在则使用默认配置自动创建一个,当然这可以通过cacheManager属性指定我们需要使用的CacheManager,CacheManager可以通过EhCacheManagerFactoryBean进行定义。此外,如果没有指定对应缓存的名称,默认将使用beanName,在上述配置中即为ehcache4UserDetails,可以通过cacheName属性进行指定。此外,缓存的配置信息也都是使用的默认的。更多关于Spring使用Ehcache的信息可以参考我的另一篇文章《Spring使用Cache》。
?
(注:本文是基于Spring Security3.1.6所写)
?
?(注:原创文章,转载请注明出处。原文地址:http://haohaoxuexi.iteye.com/blog/2159871)
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。