1.建立OnlineSessionDao繼承EnterpriseCacheSessionDAO,實現session持久化共享 java
package com.jsaas.core.security; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Collection; import org.apache.shiro.session.Session; import org.apache.shiro.session.UnknownSessionException; import org.apache.shiro.session.mgt.SimpleSession; import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO; import com.jfinal.log.Log; import com.jfinal.plugin.ehcache.CacheKit; import com.jfinal.plugin.redis.Redis; /** * @ClassName: onlineSessionDao * @Description: session管理,獲取在線用戶等(session持久化,配合nginx負載均衡,實現共享session) * @author tuozq * @date 2017年11月3日 上午9:48:01 * */ public class OnlineSessionDao extends EnterpriseCacheSessionDAO { private static final Log log = Log.getLog(OnlineSessionDao.class); //定義sessionDao緩存的前綴,能夠經過 Redis.use().getJedis().keys(OnlineSessionDao.cacheNamePrefix + "*") 獲取到sessionDao緩存的全部session public static final String cacheNamePrefix = "shiro_sessionDao_cache:"; private void set(String key, Object value){ Redis.use().set(cacheNamePrefix + key, value); } private Object get(String key){ return Redis.use().get(cacheNamePrefix + key); } private void remove(String key){ Redis.use().del(cacheNamePrefix + key); } /** * 建立session */ @Override public Serializable doCreate(Session session) { Serializable sessionId = super.doCreate(session); log.info("建立 Session:"+session.getHost() + ";" + session.getId()); set(session.getId().toString(), sessionToByte(session)); return sessionId; } /** * 刪除session */ @Override public void doDelete(Session session) { log.info("刪除 Session:"+session.getHost() + ";" + session.getId()); remove(session.getId().toString()); super.doDelete(session); } /** * 更新session的最後一次訪問時間 */ @Override public void doUpdate(Session session) throws UnknownSessionException { log.info("更新 Session:"+session.getHost() + ";" + session.getId()); set(session.getId().toString(), sessionToByte(session)); super.doUpdate(session); } /** * 獲取session */ @Override protected Session doReadSession(Serializable sessionId) { Session session = super.doReadSession(sessionId); if(session == null){ byte[] bytes = (byte[]) get(sessionId.toString()); if(bytes != null && bytes.length > 0){ session = byteToSession(bytes); } } return session; } // 把session對象轉化爲byte保存到緩存中 public byte[] sessionToByte(Session session){ ByteArrayOutputStream bo = new ByteArrayOutputStream(); byte[] bytes = null; try { ObjectOutputStream oo = new ObjectOutputStream(bo); oo.writeObject(session); bytes = bo.toByteArray(); } catch (IOException e) { e.printStackTrace(); } return bytes; } // 把byte還原爲session public Session byteToSession(byte[] bytes){ ByteArrayInputStream bi = new ByteArrayInputStream(bytes); ObjectInputStream in; SimpleSession session = null; try { in = new ObjectInputStream(bi); session = (SimpleSession) in.readObject(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return session; } }
2.使用redis接管shiro cacheManagenginx
建立RedisCacheManage類實現CacheManager接口,在shiro.ini中指定cacheManager爲RedisCacheManageweb
package com.jsaas.core.security.cache; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.apache.shiro.cache.Cache; import org.apache.shiro.cache.CacheException; import org.apache.shiro.cache.CacheManager; import com.jfinal.log.Log; import com.jfinal.plugin.redis.Redis; /** * @Title: RedisCacheManage.java * @Package com.jsaas.core.security * @Description: TODO(接管shiro緩存管理) * @author tuozq * @date 2017年12月7日 上午9:26:07 * @version V1.0 */ @SuppressWarnings({"rawtypes","unchecked"}) public class RedisCacheManage implements CacheManager { private static final Log log = Log.getLog(RedisCacheManage.class); private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap<String, Cache>(); public <K, V> Cache<K, V> getCache(String name) throws CacheException { // TODO Auto-generated method stub log.info(String.format("獲取redis %s 實例", name)); if(caches.containsKey(name)){ return caches.get(name); } RedisCache<K, V> redisCache = new RedisCache<K, V>(new RedisManage(name)); caches.put(name, redisCache); return redisCache; } }
實現shiro的cacheredis
package com.jsaas.core.security.cache; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.shiro.cache.Cache; import org.apache.shiro.cache.CacheException; import com.jfinal.log.Log; import redis.clients.jedis.Jedis; /** * @Title: RedisCache.java * @Package com.jsaas.core.security.cache * @Description: TODO(shiro緩存cache) * @author tuozq * @date 2017年12月7日 上午9:50:19 * @version V1.0 */ public class RedisCache<K, V> implements Cache<K, V> { Log log = Log.getLog(RedisCache.class); private RedisManage redisManage; public RedisCache(RedisManage redisManage){ this.redisManage = redisManage; } private com.jfinal.plugin.redis.Cache getCache(){ log.info("user cache :" + redisManage.getPrefix()); return redisManage.getCache(); } public void clear() throws CacheException { // TODO Auto-generated method stub getCache().getJedis().flushDB(); } public V get(K key) throws CacheException { // TODO Auto-generated method stub return getCache().get(redisManage.getPrefix() + key); } @SuppressWarnings("unchecked") public Set<K> keys() { // TODO Auto-generated method stub Jedis jedis = getCache().getJedis(); Set<String> keys = jedis.keys(redisManage.getPrefix() + "*"); Set<K> ks = new HashSet<K>(); for (String key : keys) { ks.add((K)key); } return ks; } public V put(K key, V value) throws CacheException { // TODO Auto-generated method stub getCache().set(redisManage.getPrefix() + key, value); return value; } public V remove(K key) throws CacheException { // TODO Auto-generated method stub V value = getCache().get(redisManage.getPrefix() + key); getCache().del(redisManage.getPrefix() + key); return value; } public int size() { // TODO Auto-generated method stub return keys().size(); } public Collection<V> values() { // TODO Auto-generated method stub Set<K> ks = keys(); List<V> vs = new ArrayList<V>(); for (K k : ks) { vs.add(get(k)); } return vs; } }
shiro redisManageapache
package com.jsaas.core.security.cache; import com.jfinal.plugin.redis.Redis; import com.jsaas.common.Constant; /** * @Title: RedisManage.java * @Package com.jsaas.core.security.cache * @Description: TODO(shiro redis 緩存管理) * @author tuozq * @date 2017年12月7日 上午11:28:31 * @version V1.0 */ public class RedisManage { private com.jfinal.plugin.redis.Cache cache; //用於區分shiro不一樣的cache name private String prefix; public RedisManage(String cachename) { // TODO Auto-generated constructor stub this.prefix = cachename + ":"; } public com.jfinal.plugin.redis.Cache getCache() { if(cache == null){ //在jfinalConfig中添加redis插件 me.add(new RedisPlugin(Constant.REDIS_SHIROMANAGE_CACHE, "127.0.0.1", 6379)); cache = Redis.use(Constant.REDIS_SHIROMANAGE_CACHE); } return cache; } public String getPrefix(){ return this.prefix; } }
3.nginx配置緩存
#配置集羣 upstream jsaas_server { server localhost:81 weight=5; server localhost:82 weight=5; } #gzip on; server { listen 80; server_name localhost; #配置代理服務器 location / { proxy_pass http://jsaas_server;# http://localhost:80/ 請求轉發到jsaas_server集羣 proxy_set_header Host $http_host; proxy_set_header Cookie $http_cookie; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; client_max_body_size 100m; proxy_connect_timeout 1;#鏈接超時時間,不能設置過長,不然服務器宕機時沒法快速切換服務器 #proxy_set_header Host $host:$server_port; }
4.shiro.ini服務器
#指定sessiondao sessionDAO = com.jsaas.core.security.OnlineSessionDao sessionDAO.activeSessionsCacheName = shiro-activeSessionCache sessionManager.sessionDAO = $sessionDAO #指定cacheManager cacheManager = com.jsaas.core.security.cache.RedisCacheManage securityManager.cacheManager = $cacheManager ###############################所有shiro配置######################################## [main] #realm #自定義Realm myRealm = com.jsaas.core.security.ShiroDbRealm securityManager.realm = $myRealm #配置shiro的密碼驗證方式爲鹽加密 也能夠經過ShiroDbRealm 中 setCredentialsMatcher方法指定自定義的密碼驗證方式 credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher credentialsMatcher.hashAlgorithmName=SHA-1 credentialsMatcher.hashIterations=1024 credentialsMatcher.storedCredentialsHexEncoded=true myRealm.credentialsMatcher=$credentialsMatcher #沒有登陸的用戶請求須要登陸的頁面時自動跳轉到登陸頁面,不是必須的屬性,不輸入地址的話會自動尋找項目web項目的根目錄下的」/login.jsp」 shiro.loginUrl = /login #登陸成功默認跳轉頁面,不配置則跳轉至」/」。若是登錄前點擊的一個須要登陸的頁面,則在登陸自動跳轉到那個須要登陸的頁面。不跳轉到此。 shiro.successUrl = /sys/user/successUrl #沒有權限默認跳轉的頁面。 shiro.unauthorizedUrl = /403 #sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager sessionManager = com.jsaas.core.security.MyWebSessionManager #ehcache #shiroCacheManager = org.apache.shiro.cache.ehcache.EhCacheManager #shiroCacheManager.cacheManagerConfigFile = classpath:ehcache.xml #securityManager.cacheManager = $shiroCacheManager #redis cache cacheManager = com.jsaas.core.security.cache.RedisCacheManage securityManager.cacheManager = $cacheManager #session #sessionDAO = org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO sessionDAO = com.jsaas.core.security.OnlineSessionDao sessionDAO.activeSessionsCacheName = shiro-activeSessionCache sessionManager.sessionDAO = $sessionDAO securityManager.sessionManager = $sessionManager securityManager.sessionManager.globalSessionTimeout = 360000 [urls] /res/** = anon /login/** = anon /user/** = anon /** = authc