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);
    }
}

授权与认证类似

posted @ 2018-05-30 18:44  BINGJJFLY  阅读(3146)  评论(0编辑  收藏  举报