【Shiro學習之七】shiro緩存


apahce shiro:1.6.0

Shiro 提供了類似於 Spring 的 Cache 抽象,即 Shiro 本身不實現 Cache,但是對 Cache 進行了又抽象,方便更換不同的底層 Cache 實現。
一、相關組件
1、Cache接口


2、CacheManager接口


3、CacheManagerAware接口用於注入CacheManager
Shiro內部相應的組件DefaultSecurityManager會自動檢測相應的對象(如Realm)是否實現了CacheManagerAware並自動注入相應的CacheManager。

二、Realm 緩存


Shiro 提供了 CachingRealm,其實現了 CacheManagerAware 接口,提供了緩存的一些基礎實現;另外 AuthenticatingRealm 及 AuthorizingRealm 分別提供了對 AuthenticationInfo和AuthorizationInfo 信息的緩存。
當用戶修改密碼或者修改權限后需要將緩存中的 AuthenticationInfo和AuthorizationInfo清除掉。

package com.github.zhangkaitao.shiro.chapter11.realm;

import com.github.zhangkaitao.shiro.chapter11.entity.User;
import com.github.zhangkaitao.shiro.chapter11.service.UserService;
import com.github.zhangkaitao.shiro.chapter11.service.UserServiceImpl;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

/**
 * <p>User: Zhang Kaitao
 * <p>Date: 14-1-28
 * <p>Version: 1.0
 */
public class UserRealm extends AuthorizingRealm {

    private UserService userService = new UserServiceImpl();

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String username = (String)principals.getPrimaryPrincipal();

        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.setRoles(userService.findRoles(username));
        authorizationInfo.setStringPermissions(userService.findPermissions(username));
        return authorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        String username = (String)token.getPrincipal();

        User user = userService.findByUsername(username);
        if(user == null) {
            throw new UnknownAccountException();//沒找到帳號
        }

        if(Boolean.TRUE.equals(user.getLocked())) {
            throw new LockedAccountException(); //帳號鎖定
        }

        //交給AuthenticatingRealm使用CredentialsMatcher進行密碼匹配,如果覺得人家的不好可以自定義實現
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                user.getUsername(), //用戶名
                user.getPassword(), //密碼
                ByteSource.Util.bytes(user.getCredentialsSalt()),//salt=username+salt
                getName()  //realm name
        );
        return authenticationInfo;
    }

    @Override
    public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
        super.clearCachedAuthorizationInfo(principals);
    }

    @Override
    public void clearCachedAuthenticationInfo(PrincipalCollection principals) {
        super.clearCachedAuthenticationInfo(principals);
    }

    @Override
    public void clearCache(PrincipalCollection principals) {
        super.clearCache(principals);
    }

    public void clearAllCachedAuthorizationInfo() {
        getAuthorizationCache().clear();
    }

    public void clearAllCachedAuthenticationInfo() {
        getAuthenticationCache().clear();
    }

    public void clearAllCache() {
        clearAllCachedAuthenticationInfo();
        clearAllCachedAuthorizationInfo();
    }

}
View Code

在某些清空下這種方式可能不是最好的選擇,可以考慮直接廢棄 Shiro 的緩存,然后自己通過如 AOP 機制實現自己的緩存;可以參考: 

https://github.com/zhangkaitao/es/tree/master/web/src/main/java/com/sishuok/es/extra/aop
另外如果和 Spring 集成時可以考慮直接使用 Spring 的 Cache 抽象,可以考慮使用SpringCacheManagerWrapper, 其對 Spring Cache 進行了包裝, 轉換為 Shiro 的 CacheManager實現:
https://github.com/zhangkaitao/es/blob/master/web/src/main/java/org/apache/shiro/cache/spring/SpringCacheManagerWrapper.java

三、Session 緩存


securityManager實現了SessionsSecurityManager,其會自動判斷 SessionManager是否實現了CacheManagerAware 接口,如果實現了會把 CacheManager 設置給它。然后sessionManager會判斷相應的sessionDAO(如繼承自 CachingSessionDAO)是否實現了CacheManagerAware, 如果實現了會把 CacheManager 設置給它。

package com.github.zhangkaitao.shiro.chapter11.session.dao;

import com.github.zhangkaitao.shiro.chapter11.JdbcTemplateUtils;
import com.github.zhangkaitao.shiro.chapter11.SerializableUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.ValidatingSession;
import org.apache.shiro.session.mgt.eis.CachingSessionDAO;
import org.springframework.jdbc.core.JdbcTemplate;

import java.io.Serializable;
import java.util.List;

/**
 * <p>User: Zhang Kaitao
 * <p>Date: 14-2-8
 * <p>Version: 1.0
 */
public class MySessionDAO extends CachingSessionDAO {

    private JdbcTemplate jdbcTemplate = JdbcTemplateUtils.jdbcTemplate();

    @Override
    protected Serializable doCreate(Session session) {
        Serializable sessionId = generateSessionId(session);
        assignSessionId(session, sessionId);
        String sql = "insert into sessions(id, session) values(?,?)";
        jdbcTemplate.update(sql, sessionId, SerializableUtils.serialize(session));
        return session.getId();
    }
    @Override
    protected void doUpdate(Session session) {
        if(session instanceof ValidatingSession && !((ValidatingSession)session).isValid()) {
            return; //如果會話過期/停止 沒必要再更新了
        }
        String sql = "update sessions set session=? where id=?";
        jdbcTemplate.update(sql, SerializableUtils.serialize(session), session.getId());
    }
    @Override
    protected void doDelete(Session session) {
        String sql = "delete from sessions where id=?";
        jdbcTemplate.update(sql, session.getId());
    }
    @Override
    protected Session doReadSession(Serializable sessionId) {
        String sql = "select session from sessions where id=?";
        List<String> sessionStrList = jdbcTemplate.queryForList(sql, String.class, sessionId);
        if(sessionStrList.size() == 0) return null;
        return SerializableUtils.deserialize(sessionStrList.get(0));
    }
}
View Code

 


免責聲明!

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



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