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

授權與認證類似


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM