Spring Security 缓存 UserDetails
admin
2023-07-30 19:53:50
0

缓存 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 的示例。

 
      
      
   
   
   
      
      
      
      
         
            
            
         
      
   
   
   
   
   
      
   

在上面的配置中,我们通过 EhcacheFactoryBean 定义的 Ehcache bean 对象采用的是默认配置,其将使用默认的 CacheManager,即直接通过 CacheManager.getInstance() 获取当前已经存在的 CacheManager 对象,如不存在则使用默认配置自动创建一个,当然这可以通过 cacheManager 属性指定我们需要使用的 CacheManager,CacheManager 可以通过 EhCacheManagerFactoryBean 进行定义。此外,如果没有指定对应缓存的名称,默认将使用 beanName,在上述配置中即为 ehcache4UserDetails,可以通过 cacheName 属性进行指定。此外,缓存的配置信息也都是使用的默认的。

相关内容

热门资讯

玻璃硬盘原理图 玻璃硬盘原理 玻璃硬盘,又称为磁头悬浮硬盘(Magnetic Head Flying Disk,MHFD),是一种...
家里监控最长能保存多少天的记录... 家里监控一般保存多久 随着科技的发展,家庭监控系统已经成为了许多家庭的必备设备,它不仅可以帮助我们...
QQ音乐提示代理模式可能无法正... QQ音乐提示代理模式可能无法正常访问,如上图所示,是怎么回事呢? 这个可能和你的网络设置有关系,首先...
闲鱼搜索规则与技巧 闲鱼最新特... 在闲鱼这个二手交易平台上,有很多用户都希望能够找到一些特殊的东西,比如一些罕见的收藏品、独特的手工艺...
别人打电话听不见我说话怎么回事... 当我们在使用手机时,可能会遇到别人打电话过来听不见声音的情况,这种情况可能是由多种原因导致的,下面我...
华为tag有用吗 华为tag-... 华为Tag是华为手机中的一种功能,它可以帮助用户更好地管理自己的手机数据和应用,通过使用华为Tag,...
ps5手柄可用手机快充充电吗 ... PS5手柄,即PlayStation 5的DualSense手柄,是索尼公司为PlayStation...
frp内网穿透配置 HTTP ... HTTP 类型的代理相比于 TCP 类型,不仅在服务端只需要监听一个额外的端口 vhost_http...
广电4k机顶盒怎么连接 广电网... 四广电网络,即四家主流的广播电视网络运营商,包括中国电信、中国移动、中国联通和中国广电,这些运营商为...
hwid是永久激活吗 hwid... HWID,全称Hardware ID,是硬件识别码的缩写,它是计算机硬件制造商为了区分每一台设备而分...