Spring+shiroマルチノードセッション共有
12097 ワード
shiro私はあまり紹介しません.私の案はshiroのsessionDAOを書き直して、sessionをredisに保存して、直接コードをつけます.
一、springでの構成
次はセッションマネージャです
sessionDAO構成およびredisManager構成
その他のshiro構成
二、javaコード
一、springでの構成
まずsecurityManagerです.webプロジェクトなので、shiroが持参したDefaultWebSecurityManagerを使用しています.ここではcacheManagerを注入する必要はありません.ソースコードを見ると、ここで配したcacheManagerは最終的にsessionDAOにセットされます.私たちは自分でsessionDAOを書くので、必要はありません.多くの人はソースコードを見ていません.ここで配したら使えると思っています.実はそうではありません.cacheManagerを有効にするには、次に構成するsessionManagerとsessionDAOはCacheManagerAwareインタフェースを実現しなければなりません.sessionModeという属性は、shiroによって廃棄され、後続のshiroバージョンがなくなる可能性があります.ここでのsessionMode属性の影響は大きく、構成の違いはsessionManagerがリセットされるかどうかに影響します.私たちは自分のsessionDAOを配合しなければなりません.すべては絶対にこの属性を配合しません.次はセッションマネージャです
sessionManager shiroのDefaultWebSessionManagerを使用して、sessionのタイムアウト時間を設定し、自分で書いたsessionを配置します.name、shiroのデフォルトはcookieによって保存されたsessionIdであり、cookieのkeyのデフォルトはJESSIONIDである.例えば、JESSIONID=5575866 c-96 e 5-4 c 34-9 b 3 c-ebe 2 c 07 fd 423であるが、tomcatまたは他の使用フレームワークはこのキー値ペアを書き換える可能性がある.JESSIONIDという名前はあまりにも通用しているため、複写されると、shiroは自然にsessionidに対応するsessionが見つからない.これにより、ログインページにジャンプしたり、セッションに格納されているパラメータを取得したりして取得できないなどの一連の問題が発生し、この問題を回避するためにクッキーのnameが構成されるsessionDAO構成およびredisManager構成
redisManagerは主にredisにアクセスするために使われています.もちろんspringが提供するredisのtemplateも使えます.私はどうせ成功しなかったので、興味のある友达が試してみました.その他のshiro構成
/login = anon
/captcha.png = anon
/toLogin = anon
/logout = logout
/static/** = anon
/weixin/** = anon
/cxf/** = anon
/api/oauth2/**=anon
/api/** = anon ,tkf
/** = authc
二、javaコード
public class RedisSessionDAO extends AbstractSessionDAO {
private static Logger logger = LoggerFactory.getLogger(RedisSessionDAO.class);
private RedisManager redisManager;
/**
* The Redis key prefix for the sessions
*/
private String keyPrefix = "shiro_redis_session:";
@Override
public void update(Session session) throws UnknownSessionException {
this.saveSession(session);
}
/**
* save session
* @param session
* @throws UnknownSessionException
*/
private void saveSession(Session session) throws UnknownSessionException{
if(session == null || session.getId() == null){
logger.error("session or session id is null");
return;
}
byte[] key = getByteKey(session.getId());
byte[] value = SerializeUtils.serialize(session);
session.setTimeout(redisManager.getExpire()*1000);
this.redisManager.set(key, value, redisManager.getExpire());
}
@Override
public void delete(Session session) {
if(session == null || session.getId() == null){
logger.error("session or session id is null");
return;
}
redisManager.del(this.getByteKey(session.getId()));
}
@Override
public Collection getActiveSessions() {
Set sessions = new HashSet();
Set keys = redisManager.keys(this.keyPrefix + "*");
if(keys != null && keys.size()>0){
for(byte[] key:keys){
Session s = (Session)SerializeUtils.deserialize(redisManager.get(key));
sessions.add(s);
}
}
return sessions;
}
@Override
protected Serializable doCreate(Session session) {
Serializable sessionId = this.generateSessionId(session);
this.assignSessionId(session, sessionId);
this.saveSession(session);
return sessionId;
}
@Override
protected Session doReadSession(Serializable sessionId) {
if(sessionId == null){
logger.error("session id is null");
return null;
}
Session s = (Session)SerializeUtils.deserialize(redisManager.get(this.getByteKey(sessionId)));
return s;
}
/**
* byte[] key
* @param key
* @return
*/
private byte[] getByteKey(Serializable sessionId){
String preKey = this.keyPrefix + sessionId;
return preKey.getBytes();
}
public RedisManager getRedisManager() {
return redisManager;
}
public void setRedisManager(RedisManager redisManager) {
this.redisManager = redisManager;
/**
* redisManager
*/
this.redisManager.init();
}
/**
* Returns the Redis session keys
* prefix.
* @return The prefix
*/
public String getKeyPrefix() {
return keyPrefix;
}
/**
* Sets the Redis sessions key
* prefix.
* @param keyPrefix The prefix
*/
public void setKeyPrefix(String keyPrefix) {
this.keyPrefix = keyPrefix;
}
}
セッションを保存する際、毎回セッションの有効期限が再設定されているので、本来なら不要なはずですが、保険のためでしょうpublic class RedisManager {
private String host = "127.0.0.1";
private int port = 6379;
// 0 - never expire
private int expire = 0;
//timeout for jedis try to connect to redis server, not expire time! In milliseconds
private int timeout = 0;
private String password = "";
private static JedisPool jedisPool = null;
public RedisManager(){
}
/**
*
*/
public void init(){
if(jedisPool == null){
if(password != null && !"".equals(password)){
jedisPool = new JedisPool(new JedisPoolConfig(), host, port, timeout, password);
}else if(timeout != 0){
jedisPool = new JedisPool(new JedisPoolConfig(), host, port,timeout);
}else{
jedisPool = new JedisPool(new JedisPoolConfig(), host, port);
}
}
}
/**
* get value from redis
* @param key
* @return
*/
public byte[] get(byte[] key){
byte[] value = null;
Jedis jedis = jedisPool.getResource();
try{
value = jedis.get(key);
}finally{
//jedisPool.returnResource(jedis); , [B cannot be cast to java.lang.Long]
jedis.close();
}
return value;
}
/**
* set
* @param key
* @param value
* @return
*/
public byte[] set(byte[] key,byte[] value){
Jedis jedis = jedisPool.getResource();
try{
jedis.set(key,value);
if(this.expire != 0){
jedis.expire(key, this.expire);
}
}finally{
jedis.close();
}
return value;
}
/**
* set
* @param key
* @param value
* @param expire
* @return
*/
public byte[] set(byte[] key,byte[] value,int expire){
Jedis jedis = jedisPool.getResource();
try{
jedis.set(key,value);
if(expire != 0){
jedis.expire(key, expire);
}
}finally{
jedis.close();
}
return value;
}
/**
* del
* @param key
*/
public void del(byte[] key){
Jedis jedis = jedisPool.getResource();
try{
jedis.del(key);
}finally{
jedis.close();
}
}
/**
* flush
*/
public void flushDB(){
Jedis jedis = jedisPool.getResource();
try{
jedis.flushDB();
}finally{
jedis.close();
}
}
/**
* size
*/
public Long dbSize(){
Long dbSize = 0L;
Jedis jedis = jedisPool.getResource();
try{
dbSize = jedis.dbSize();
}finally{
jedis.close();
}
return dbSize;
}
/**
* keys
* @param regex
* @return
*/
public Set keys(String pattern){
Set keys = null;
Jedis jedis = jedisPool.getResource();
try{
keys = jedis.keys(pattern.getBytes());
}finally{
jedis.close();
}
return keys;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public int getExpire() {
return expire;
}
public void setExpire(int expire) {
this.expire = expire;
}
public int getTimeout() {
return timeout;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
シーケンス化用utilクラスpublic class SerializeUtils {
private static Logger logger = LoggerFactory.getLogger(SerializeUtils.class);
/**
*
* @param bytes
* @return
*/
public static Object deserialize(byte[] bytes) {
Object result = null;
if (isEmpty(bytes)) {
return null;
}
try {
ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes);
try {
ObjectInputStream objectInputStream = new ObjectInputStream(byteStream);
try {
result = objectInputStream.readObject();
}
catch (ClassNotFoundException ex) {
throw new Exception("Failed to deserialize object type", ex);
}
}
catch (Throwable ex) {
throw new Exception("Failed to deserialize", ex);
}
} catch (Exception e) {
logger.error("Failed to deserialize",e);
}
return result;
}
public static boolean isEmpty(byte[] data) {
return (data == null || data.length == 0);
}
/**
*
* @param object
* @return
*/
public static byte[] serialize(Object object) {
byte[] result = null;
if (object == null) {
return new byte[0];
}
try {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream(128);
try {
if (!(object instanceof Serializable)) {
throw new IllegalArgumentException(SerializeUtils.class.getSimpleName() + " requires a Serializable payload " +
"but received an object of type [" + object.getClass().getName() + "]");
}
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteStream);
objectOutputStream.writeObject(object);
objectOutputStream.flush();
result = byteStream.toByteArray();
}
catch (Throwable ex) {
throw new Exception("Failed to serialize", ex);
}
} catch (Exception ex) {
logger.error("Failed to serialize",ex);
}
return result;
}
}