/login.htm=anon
/logout.htm=logout
/unauthorized.htm=anon
/** = authc,perms
===== SerializeUtil.java =====
package com.gxx.manage.shiro;
import java.io.*;
/**
*
* - Title:
* -
* 序列化工具类
*
* - Description:
* -
*
none
*
*
*
* @author Administrator
* @version 1.0, 2015年9月22日
* @since manage
*
*/
public class SerializeUtil {
public static byte[] serialize(Object value) {
if (value == null) {
throw new NullPointerException("Can't serialize null");
}
byte[] rv = null;
ByteArrayOutputStream bos = null;
ObjectOutputStream os = null;
try {
bos = new ByteArrayOutputStream();
os = new ObjectOutputStream(bos);
os.writeObject(value);
os.close();
bos.close();
rv = bos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
System.out.println("serialize error");
} finally {
close(os);
close(bos);
}
return rv;
}
public static Object deserialize(byte[] in) {
return deserialize(in, Object.class);
}
@SuppressWarnings("unchecked")
public static T deserialize(byte[] in, Class requiredType) {
Object rv = null;
ByteArrayInputStream bis = null;
ObjectInputStream is = null;
try {
if (in != null) {
bis = new ByteArrayInputStream(in);
is = new ObjectInputStream(bis);
rv = is.readObject();
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("deserialize error");
} finally {
close(is);
close(bis);
}
return (T) rv;
}
private static void close(Closeable closeable) {
if (closeable != null)
try {
closeable.close();
} catch (IOException e) {
e.printStackTrace();
System.out.println("close stream error");
}
}
}
===== JedisManager.java =====
package com.gxx.manage.shiro;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.exceptions.JedisConnectionException;
/**
*
* - Title:
* -
* Jedis工具类
*
* - Description:
* -
*
none
*
*
*
* @author Administrator
* @version 1.0, 2015年9月22日
* @since manage
*
*/
public class JedisManager {
private JedisPool jedisPool;
public Jedis getJedis() {
Jedis jedis = null;
try {
jedis = getJedisPool().getResource();
} catch (Exception e) {
throw new JedisConnectionException(e);
}
return jedis;
}
public void returnResource(Jedis jedis, boolean isBroken) {
if (jedis == null)
return;
if (isBroken)
getJedisPool().returnBrokenResource(jedis);
else
getJedisPool().returnResource(jedis);
}
public byte[] getValueByKey(int dbIndex, byte[] key) throws Exception {
Jedis jedis = null;
byte[] result = null;
boolean isBroken = false;
try {
jedis = getJedis();
jedis.select(dbIndex);
result = jedis.get(key);
} catch (Exception e) {
isBroken = true;
throw e;
} finally {
returnResource(jedis, isBroken);
}
return result;
}
public void deleteByKey(int dbIndex, byte[] key) throws Exception {
Jedis jedis = null;
boolean isBroken = false;
try {
jedis = getJedis();
jedis.select(dbIndex);
jedis.del(key);
} catch (Exception e) {
isBroken = true;
throw e;
} finally {
returnResource(jedis, isBroken);
}
}
public void saveValueByKey(int dbIndex, byte[] key, byte[] value, int expireTime)
throws Exception {
Jedis jedis = null;
boolean isBroken = false;
try {
jedis = getJedis();
jedis.select(dbIndex);
jedis.set(key, value);
if (expireTime > 0)
jedis.expire(key, expireTime);
} catch (Exception e) {
isBroken = true;
throw e;
} finally {
returnResource(jedis, isBroken);
}
}
public JedisPool getJedisPool() {
return jedisPool;
}
public void setJedisPool(JedisPool jedisPool) {
/**
* 配置文件注入有问题,这里手动创建
* TODO
*/
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(1000);
config.setMaxIdle(600);
config.setMinIdle(300);
config.setTestOnBorrow(true);
JedisPool pool = new JedisPool(config, "121.43.104.34", 6379, 20000);
this.jedisPool = pool;
}
}
===== CustomShiroSessionDAO.java =====
package com.gxx.manage.shiro.session;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import java.io.Serializable;
import java.util.Collection;
/**
*
* - Title:
* -
* 自定义shiro会话DAO
*
* - Description:
* -
*
none
*
*
*
* @author Administrator
* @version 1.0, 2015年9月22日
* @since manage
*
*/
public class CustomShiroSessionDAO extends AbstractSessionDAO {
private ShiroSessionRepository shiroSessionRepository;
@Override
public void update(Session session) throws UnknownSessionException {
getShiroSessionRepository().saveSession(session);
}
@Override
public void delete(Session session) {
if (session == null) {
return;
}
Serializable id = session.getId();
if (id != null) {
getShiroSessionRepository().deleteSession(id);
}
//TODO if session is too large,when session destory clear shiro cache
}
@Override
public Collection getActiveSessions() {
return getShiroSessionRepository().getAllSessions();
}
@Override
protected Serializable doCreate(Session session) {
Serializable sessionId = this.generateSessionId(session);
this.assignSessionId(session, sessionId);
getShiroSessionRepository().saveSession(session);
return sessionId;
}
@Override
protected Session doReadSession(Serializable sessionId) {
return getShiroSessionRepository().getSession(sessionId);
}
public ShiroSessionRepository getShiroSessionRepository() {
return shiroSessionRepository;
}
public void setShiroSessionRepository(
ShiroSessionRepository shiroSessionRepository) {
this.shiroSessionRepository = shiroSessionRepository;
}
}
===== JedisShiroSessionRepository.java =====
package com.gxx.manage.shiro.session;
import java.io.Serializable;
import java.util.Collection;
import org.apache.shiro.session.Session;
import com.gxx.manage.shiro.JedisManager;
import com.gxx.manage.shiro.SerializeUtil;
/**
*
* - Title:
* -
* Jedis实现shiro会话管理接口
*
* - Description:
* -
*
none
*
*
*
* @author Administrator
* @version 1.0, 2015年9月22日
* @since manage
*
*/
public class JedisShiroSessionRepository implements ShiroSessionRepository {
private static final String REDIS_SHIRO_SESSION = "shiro-session:";
private static final int SESSION_VAL_TIME_SPAN = 18000;
private static final int DB_INDEX = 0;
private JedisManager jedisManager;
@Override
public void saveSession(Session session) {
if (session == null || session.getId() == null)
throw new NullPointerException("session is empty");
try {
byte[] key = SerializeUtil.serialize(buildRedisSessionKey(session.getId()));
byte[] value = SerializeUtil.serialize(session);
long sessionTimeOut = session.getTimeout() / 1000;
Long expireTime = sessionTimeOut + SESSION_VAL_TIME_SPAN + (5 * 60);
getJedisManager().saveValueByKey(DB_INDEX, key, value, expireTime.intValue());
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void deleteSession(Serializable id) {
if (id == null) {
throw new NullPointerException("session id is empty");
}
try {
getJedisManager().deleteByKey(DB_INDEX,
SerializeUtil.serialize(buildRedisSessionKey(id)));
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public Session getSession(Serializable id) {
if (id == null)
throw new NullPointerException("session id is empty");
Session session = null;
try {
byte[] value = getJedisManager().getValueByKey(DB_INDEX, SerializeUtil
.serialize(buildRedisSessionKey(id)));
session = SerializeUtil.deserialize(value, Session.class);
} catch (Exception e) {
e.printStackTrace();
}
return session;
}
@Override
public Collection getAllSessions() {
//TODO
return null;
}
private String buildRedisSessionKey(Serializable sessionId) {
return REDIS_SHIRO_SESSION + sessionId;
}
public JedisManager getJedisManager() {
return jedisManager;
}
public void setJedisManager(JedisManager jedisManager) {
this.jedisManager = jedisManager;
}
}
===== ShiroSessionRepository.java =====
package com.gxx.manage.shiro.session;
import org.apache.shiro.session.Session;
import java.io.Serializable;
import java.util.Collection;
/**
*
* - Title:
* -
* 自定义shiro会话管理接口
*
* - Description:
* -
*
none
*
*
*
* @author Administrator
* @version 1.0, 2015年9月22日
* @since manage
*
*/
public interface ShiroSessionRepository {
void saveSession(Session session);
void deleteSession(Serializable sessionId);
Session getSession(Serializable sessionId);
Collection getAllSessions();
}
===== CustomShiroCacheManager.java =====
package com.gxx.manage.shiro.cache;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.util.Destroyable;
/**
*
* - Title:
* -
* shiro缓存管理类
*
* - Description:
* -
*
none
*
*
*
* @author Administrator
* @version 1.0, 2015年9月22日
* @since manage
*
*/
public class CustomShiroCacheManager implements CacheManager, Destroyable {
private ShiroCacheManager shiroCacheManager;
@Override
public Cache getCache(String name) throws CacheException {
return getShiroCacheManager().getCache(name);
}
@Override
public void destroy() throws Exception {
shiroCacheManager.destroy();
}
public ShiroCacheManager getShiroCacheManager() {
return shiroCacheManager;
}
public void setShiroCacheManager(ShiroCacheManager shiroCacheManager) {
this.shiroCacheManager = shiroCacheManager;
}
}
===== JedisShiroCache.java =====
package com.gxx.manage.shiro.cache;
import java.util.Collection;
import java.util.Set;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import com.gxx.manage.shiro.JedisManager;
import com.gxx.manage.shiro.SerializeUtil;
/**
*
* - Title:
* -
* Jedis实现Shiro缓存
*
* - Description:
* -
*
none
*
*
*
* @author Administrator
* @version 1.0, 2015年9月22日
* @since manage
*
*/
public class JedisShiroCache implements Cache {
private static final String REDIS_SHIRO_CACHE = "shiro-cache:";
private static final int DB_INDEX = 1;
private JedisManager jedisManager;
private String name;
public JedisShiroCache(String name, JedisManager jedisManager) {
this.name = name;
this.jedisManager = jedisManager;
}
/**
* 自定义relm中的授权/认证的类名加上授权/认证英文名字
*/
public String getName() {
if (name == null)
return "";
return name;
}
public void setName(String name) {
this.name = name;
}
@SuppressWarnings("unchecked")
@Override
public V get(K key) throws CacheException {
byte[] byteKey = SerializeUtil.serialize(buildCacheKey(key));
byte[] byteValue = new byte[0];
try {
byteValue = jedisManager.getValueByKey(DB_INDEX, byteKey);
} catch (Exception e) {
e.printStackTrace();
System.out.println("get cache error");
}
return (V) SerializeUtil.deserialize(byteValue);
}
@Override
public V put(K key, V value) throws CacheException {
V previos = get(key);
try {
jedisManager.saveValueByKey(DB_INDEX, SerializeUtil.serialize(buildCacheKey(key)),
SerializeUtil.serialize(value), -1);
} catch (Exception e) {
e.printStackTrace();
System.out.println("put cache error");
}
return previos;
}
@Override
public V remove(K key) throws CacheException {
V previos = get(key);
try {
jedisManager.deleteByKey(DB_INDEX, SerializeUtil.serialize(buildCacheKey(key)));
} catch (Exception e) {
e.printStackTrace();
System.out.println("remove cache error");
}
return previos;
}
@Override
public void clear() throws CacheException {
//TODO
}
@Override
public int size() {
if (keys() == null)
return 0;
return keys().size();
}
@Override
public Set keys() {
//TODO
return null;
}
@Override
public Collection values() {
//TODO
return null;
}
private String buildCacheKey(Object key) {
return REDIS_SHIRO_CACHE + getName() + ":" + key;
}
}
===== JedisShiroCacheManager.java =====
package com.gxx.manage.shiro.cache;
import org.apache.shiro.cache.Cache;
import com.gxx.manage.shiro.JedisManager;
/**
*
* - Title:
* -
* Jedis实现shiro缓存管理接口
*
* - Description:
* -
*
none
*
*
*
* @author Administrator
* @version 1.0, 2015年9月22日
* @since manage
*
*/
public class JedisShiroCacheManager implements ShiroCacheManager {
private JedisManager jedisManager;
@Override
public Cache getCache(String name) {
return new JedisShiroCache(name, getJedisManager());
}
@Override
public void destroy() {
getJedisManager().getJedis().shutdown();
}
public JedisManager getJedisManager() {
return jedisManager;
}
public void setJedisManager(JedisManager jedisManager) {
this.jedisManager = jedisManager;
}
}
===== ShiroCacheManager.java =====
package com.gxx.manage.shiro.cache;
import org.apache.shiro.cache.Cache;
/**
*
* - Title:
* -
* shiro缓存管理接口
*
* - Description:
* -
*
none
*
*
*
* @author Administrator
* @version 1.0, 2015年9月22日
* @since manage
*
*/
public interface ShiroCacheManager {
Cache getCache(String name);
void destroy();
}
===== SessionController.java =====
package com.gxx.manage.web.session;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* UserController
*
* @author gxx
*/
@Controller
@RequestMapping("/session/")
public class SessionController {
/**
* 日志处理器
*/
private final Logger logger = Logger.getLogger(SessionController.class);
/**
* 设置session
* @param request
* @return
*/
@RequestMapping(value = "/set",produces="application/json")
public @ResponseBody Map set(HttpServletRequest request) {
logger.info("设置session:key=[" + request.getParameter("key") + "],value=[" + request.getParameter("value") + "]");
/**
* 设置session
*/
Subject currentUser = SecurityUtils.getSubject();
Session session = currentUser.getSession();
session.setAttribute(request.getParameter("key"), request.getParameter("value"));
/**
* 返回结果
*/
Map resultMap = new HashMap();
resultMap.put("success", true);
return resultMap;
}
/**
* 获取session
* @param request
* @return
*/
@RequestMapping(value = "/get",produces="application/json")
public @ResponseBody Map get(HttpServletRequest request) {
logger.info("获取session:key=[" + request.getParameter("key") + "]");
/**
* 设置session
*/
Subject currentUser = SecurityUtils.getSubject();
Session session = currentUser.getSession();
Object value = session.getAttribute(request.getParameter("key"));
logger.info("获取session:value=[" + value + "]");
/**
* 返回结果
*/
Map resultMap = new HashMap();
resultMap.put("success", true);
resultMap.put("value", value);
return resultMap;
}
}
===== 数据库数据截图 =====
{{:分享:技术:shiro:permission_1.png?300|}}
{{:分享:技术:shiro:role_permission_1.png?300|}}
===== 代码操作 =====
原来操作session是:
request.getSession().setAttribute("K","V");
request.getSession().getAttribute("K");
shiro操作session是:
Subject currentUser = SecurityUtils.getSubject();
Session session = currentUser.getSession();
session.setAttribute("K","V");
session.getAttribute("K");
===== 无状态节点重启依然保存会话 =====
有了shiro之后,会话的存取就不依赖容器了,各个应用节点就是无状态的,所有的会话存储都在redis中,即使容器挂掉,重启之后,用户从redis中读取会话信息依然可以保持登录状态以及获取之前设置的session数据,只要redis不挂(redis可以本地持久化,如果有必要redis还可以做集群)。
===== 不同节点共享会话 =====
同一机器下,不同端口P1和P2两个tomcat T1和T2,都部署相同的应用manage,指向同一个redis。T1访问登录成功,T2可以直接访问登录后页面;T1设置session的键Key和值Value,T2可以直接通过键Key取到对应的值Value。