Shiro 缓存认证信息和授权信息
spring-shiro.xml文件配置
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="customAuthorizingRealm"/> <property name="cacheManager" ref="ehCacheManager"/> </bean> <bean id="ehCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> <property name="cacheManagerConfigFile" value="classpath:shiro/ehcache.xml"/> <bean/> <bean id="customAuthorizingRealm" class="com.wjz.demo.CustomAuthorizingRealm"> <property name="authenticationCachingEnabled" value="true"/> <property name="authorizationCachingEnabled" value="true"/> </bean>
缓存原理
CachingSecurityManager
注入缓存管理器到安全管理器中,还需要将缓存管理器注入到领域中
public void setCacheManager(CacheManager cacheManager) { this.cacheManager = cacheManager; afterCacheManagerSet(); }
RealmSecurityManager
protected void afterCacheManagerSet() { super.afterCacheManagerSet(); applyCacheManagerToRealms(); }
将缓存管理器注入到领域中,存入取出缓存内容均有领域具体实现
protected void applyCacheManagerToRealms() {
// 获得由配置部分注入的EhCacheManager CacheManager cacheManager = getCacheManager(); Collection<Realm> realms = getRealms(); if (cacheManager != null && realms != null && !realms.isEmpty()) { for (Realm realm : realms) { if (realm instanceof CacheManagerAware) {
// 将EhCacheManage注入到Realm中 ((CacheManagerAware) realm).setCacheManager(cacheManager); } } } }
DefaultSecurityManager开始认证
public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException { AuthenticationInfo info; try { info = authenticate(token); } catch (AuthenticationException ae) { try { onFailedLogin(token, ae, subject); } catch (Exception e) { if (log.isInfoEnabled()) { log.info("onFailedLogin method threw an " + "exception. Logging and propagating original AuthenticationException.", e); } } throw ae; //propagate } Subject loggedIn = createSubject(token, info, subject); onSuccessfulLogin(token, info, loggedIn); return loggedIn; }
public AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException { return this.authenticator.authenticate(token); }
获得我们自定义的Realm领域如CustomAuthorizingRealm
protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException { assertRealmsConfigured(); Collection<Realm> realms = getRealms(); if (realms.size() == 1) { return doSingleRealmAuthentication(realms.iterator().next(), authenticationToken); } else { return doMultiRealmAuthentication(realms, authenticationToken); } }
从缓存中找认证信息,如果没有找到则执行CustomAuthorizingRealm中的doGetAuthenticationInfo方法获得AuthenticationInfo
public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { // 试图从缓存中获得AuthenticationInfo,后文详解#1 AuthenticationInfo info = getCachedAuthenticationInfo(token); if (info == null) { //otherwise not cached, perform the lookup: info = doGetAuthenticationInfo(token); log.debug("Looked up AuthenticationInfo [{}] from doGetAuthenticationInfo", info); if (token != null && info != null) {
// 将获得的AuthenticationInfo放入缓存,后文详解#2 cacheAuthenticationInfoIfPossible(token, info); } } else { log.debug("Using cached authentication info [{}] to perform credentials matching.", info); } if (info != null) { assertCredentialsMatch(token, info); } else { log.debug("No AuthenticationInfo found for submitted AuthenticationToken [{}]. Returning null.", token); } return info; }
书接前文#1
试图从缓存中获得AuthenticationInfo
private AuthenticationInfo getCachedAuthenticationInfo(AuthenticationToken token) { AuthenticationInfo info = null; // 获得可用的缓存,后文详解#1-1 Cache<Object, AuthenticationInfo> cache = getAvailableAuthenticationCache(); if (cache != null && token != null) { log.trace("Attempting to retrieve the AuthenticationInfo from cache.");
// 以用户名为key Object key = getAuthenticationCacheKey(token);
// 根据key从缓存中拿到AuthenticationInfo,后文详解#1-2 info = cache.get(key); if (info == null) { log.trace("No AuthorizationInfo found in cache for key [{}]", key); } else { log.trace("Found cached AuthorizationInfo for key [{}]", key); } } return info; }
书接前文#1-1
AuthenticatingRealm中有一个Cache<Object, AuthenticationInfo> authenticationCache属性
private Cache<Object, AuthenticationInfo> getAvailableAuthenticationCache() {
// 获得authenticationCache Cache<Object, AuthenticationInfo> cache = getAuthenticationCache();
// 默认为false,需要set注入为true,参考配置部分 boolean authcCachingEnabled = isAuthenticationCachingEnabled(); if (cache == null && authcCachingEnabled) {
// 使用CacheManager获得Cache对象 cache = getAuthenticationCacheLazy(); } return cache; }
获得EhCacheManager并使用它获得缓存
private Cache<Object, AuthenticationInfo> getAuthenticationCacheLazy() { if (this.authenticationCache == null) { log.trace("No authenticationCache instance set. Checking for a cacheManager..."); // 获得EhCacheManager CacheManager cacheManager = getCacheManager(); if (cacheManager != null) {
// 获得缓存的name String cacheName = getAuthenticationCacheName(); log.debug("CacheManager [{}] configured. Building authentication cache '{}'", cacheManager, cacheName);
// 根据缓存的name获得缓存 this.authenticationCache = cacheManager.getCache(cacheName); } } return this.authenticationCache; }
EhCacheManager
public final <K, V> Cache<K, V> getCache(String name) throws CacheException { if (log.isTraceEnabled()) { log.trace("Acquiring EhCache instance named [" + name + "]"); } try {
// ensureCacheManager()获得net.sf.ehcache.CacheManager net.sf.ehcache.Ehcache cache = ensureCacheManager().getEhcache(name); if (cache == null) { if (log.isInfoEnabled()) { log.info("Cache with name '{}' does not yet exist. Creating now.", name); }
// 调用net.sf.ehcache的API this.manager.addCache(name); cache = manager.getCache(name); if (log.isInfoEnabled()) { log.info("Added EhCache named [" + name + "]"); } } else { if (log.isInfoEnabled()) { log.info("Using existing EHCache named [" + cache.getName() + "]"); } }
// 封装net.sf.ehcache为shiro的org.apache.shiro.cache.ehcache.EhCache return new EhCache<K, V>(cache); } catch (net.sf.ehcache.CacheException e) { throw new CacheException(e); } }
net.sf.ehcache.Ehcache
private net.sf.ehcache.Ehcache cache; /** * Constructs a new EhCache instance with the given cache. * * @param cache - delegate EhCache instance this Shiro cache instance will wrap. */ public EhCache(net.sf.ehcache.Ehcache cache) { if (cache == null) { throw new IllegalArgumentException("Cache argument cannot be null."); } this.cache = cache; }
书接前文#1-2
shiro的EhCache内部装备一个net.sf.ehcache.Ehcache
public V get(K key) throws CacheException { try { if (log.isTraceEnabled()) { log.trace("Getting object from cache [" + cache.getName() + "] for key [" + key + "]"); } if (key == null) { return null; } else {
// 使用net.sf.ehcache.Ehcache的API获得Element Element element = cache.get(key); if (element == null) { if (log.isTraceEnabled()) { log.trace("Element for [" + key + "] is null."); } return null; } else { // 获得缓存中的内容 return (V) element.getObjectValue(); } } } catch (Throwable t) { throw new CacheException(t); } }
书接前文#2
将获得的AuthenticationInfo放入缓存
private void cacheAuthenticationInfoIfPossible(AuthenticationToken token, AuthenticationInfo info) {
// 判断是否开启了缓存功能及缓存授权功能 if (!isAuthenticationCachingEnabled(token, info)) { log.debug("AuthenticationInfo caching is disabled for info [{}]. Submitted token: [{}].", info, token); //return quietly, caching is disabled for this token/info pair: return; } Cache<Object, AuthenticationInfo> cache = getAvailableAuthenticationCache(); if (cache != null) { Object key = getAuthenticationCacheKey(token); cache.put(key, info); log.trace("Cached AuthenticationInfo for continued authentication. key=[{}], value=[{}].", key, info); } }
authenticationCachingEnabled的值默认为false需要set注入为true,cachingEnabled默认为true
public boolean isAuthenticationCachingEnabled() { return this.authenticationCachingEnabled && isCachingEnabled(); }
放入缓存
public V put(K key, V value) throws CacheException { if (log.isTraceEnabled()) { log.trace("Putting object in cache [" + cache.getName() + "] for key [" + key + "]"); } try { V previous = get(key); Element element = new Element(key, value); cache.put(element); return previous; } catch (Throwable t) { throw new CacheException(t); } }
授权与认证类似