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">

      <!-- 使用可以緩存UserDetailsCachingUserDetailsService -->

      <security:authentication-provider

         user-service-ref="cachingUserDetailsService" />

   </security:authentication-manager>

   <!-- 可以緩存UserDetailsUserDetailsService -->

   <bean id="cachingUserDetailsService"class="org.springframework.security.config.authentication.CachingUserDetailsService">

      <!-- 真正加載UserDetailsUserDetailsService -->

      <constructor-arg ref="userDetailsService"/>

      <!-- 緩存UserDetailsUserCache -->

      <property name="userCache">

         <beanclass="org.springframework.security.core.userdetails.cache.EhCacheBasedUserCache">

            <!-- 用於真正緩存的Ehcache對象 -->

            <property name="cache" ref="ehcache4UserDetails"/>

         </bean>

      </property>

   </bean>

   <!-- 將使用默認的CacheManager創建一個名爲ehcache4UserDetailsEhcache對象 -->

   <bean id="ehcache4UserDetails"class="org.springframework.cache.ehcache.EhCacheFactoryBean"/>

   <!-- 從數據庫加載UserDetailsUserDetailsService -->

   <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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章