redisはセッション共有を実現し、単一のログインを実現する

14199 ワード

会社には既存のログインシステムがあり、現在は複数のシステムを実現して単点ログインを実現する必要があり、githubで実現可能なプロジェクトに出会って、ここで記録をします.
考え方:
ユーザーが統一的な単点ログインを使用する場合、バックグラウンドでユーザーと用木のパスワードを検証し、検証を通過し、sessionidを生成し、現在ログインしているユーザーの情報をredisに、ユーザーが再ログインしたときにcookieのsessionidを取得し、redisに行って現在のユーザーが存在するかどうかを照会し、存在する場合は、すでにログインし、存在しない場合は、ログインしていません.
実装:
構築環境:IDEA 2017.2+redis+mysql5.7+springboot+jdk1.8+tomcat8.0
ログインコントローラ:
 @RequestMapping("/doLogin")
 public String doLogin(HttpServletRequest request,HttpServletResponse response,RedirectAttributes redirectAttributes,String username,String password) {
        // login success    Omit login code
        XxlUser xxlUser = new XxlUser();
        xxlUser.setUserid(existUser.getId());
        xxlUser.setUsername(existUser.getUsername());

        String sessionId = UUID.randomUUID().toString();//  uuid   session id

        SsoLoginHelper.login(response, sessionId, xxlUser);//

        // success redirect
        String redirectUrl = request.getParameter(Conf.REDIRECT_URL);
        if (StringUtils.isNotBlank(redirectUrl)) {
            String redirectUrlFinal = redirectUrl + "?" + Conf.SSO_SESSIONID + "=" + sessionId;
            return "redirect:" + redirectUrlFinal;
        } else {
            return "redirect:/";
        }
    }

ユーザーがログインしたセッションとユーザーの情報をそれぞれクッキーとredisに書き込む
    /**
     * client login (web)
     * @param response
     * @param sessionId
     * @param xxlUser
     */
    public static void login(HttpServletResponse response,String sessionId,XxlUser xxlUser) {
        SsoLoginStore.put(sessionId, xxlUser);
        CookieUtil.set(response, Conf.SSO_SESSIONID, sessionId, false);
    }
redisとcookieの具体的なツールクラス:
package com.xxl.sso.core.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisShardInfo;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPool;

import java.io.*;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;


/**
 * Redis client base on jedis         ,
 * jedis      :JedisSimpleFactry/JedisPoolFactry/ShardedJedisPoolFactry
 * 
 * @author xuxueli 2015-7-10 18:34:07
 *
 * 	# for redis (sharded.jedis.address=host01:port,host02:port)
 *	sharded.jedis.address=127.0.0.1:6379,127.0.0.1:6379,127.0.0.1:6379
 *
 */
public class JedisUtil {
	private static Logger logger = LoggerFactory.getLogger(JedisUtil.class);

	private static final int DEFAULT_EXPIRE_TIME = 7200; //       ,  / , 60*60*2=2H,    
	private static String address;
	public static void init(String address){
		JedisUtil.address = address;
	}

	// ------------------------ ShardedJedisPool ------------------------
	/**
	 *	  01: Redis    + Jedis   : Redis       , Jedis         》》      
	 * 		new Jedis("127.0.0.1", 6379).get("cache_key");
	 *	  02: Redis    + JedisPool       》》 Redis       ,        
	 * 		new JedisPool(new JedisPoolConfig(), "127.0.0.1", 6379, 10000).getResource().get("cache_key");
	 *    03: Redis  (  client   ,         ) + Jedis       》》Redis  ,       , ShardedJedisPool       ,    ,    
	 *  	new ShardedJedisPool(new JedisPoolConfig(), new LinkedList());
     */

	private static ShardedJedisPool shardedJedisPool;
	private static ReentrantLock INSTANCE_INIT_LOCL = new ReentrantLock(false);

	/**
	 *   ShardedJedis  
	 * @return
	 */
	private static ShardedJedis getInstance() {
		if (shardedJedisPool == null) {
			try {
				if (INSTANCE_INIT_LOCL.tryLock(2, TimeUnit.SECONDS)){

					try {

						if (shardedJedisPool == null) {
							// JedisPoolConfig
							JedisPoolConfig config = new JedisPoolConfig();
							config.setMaxTotal(200);			//      ,   8 
							config.setMaxIdle(50);				//        ,   8 
							config.setMinIdle(8);				//        
							config.setMaxWaitMillis(10000);		//              (        BlockWhenExhausted),        ,    :        ,    -1
							config.setTestOnBorrow(true);		//              ,   false
							config.setTestOnReturn(true);       //   returnObject   ,        
							config.setTestWhileIdle(true);		// Idle       
							config.setTimeBetweenEvictionRunsMillis(30000);	//  idle object evitor       sleep    
							config.setNumTestsPerEvictionRun(10);			//  idle object evitor           
							config.setMinEvictableIdleTimeMillis(60000);	//           idle       ,     idle object evitor     ;      timeBetweenEvictionRunsMillis  0     

							// JedisShardInfo List
							List jedisShardInfos = new LinkedList();

							String[] addressArr = address.split(",");
							for (int i = 0; i < addressArr.length; i++) {
								String[] addressInfo = addressArr[i].split(":");
								String host = addressInfo[0];
								int port = Integer.valueOf(addressInfo[1]);
								JedisShardInfo jedisShardInfo = new JedisShardInfo(host, port, 10000);
                                jedisShardInfo.setPassword("123456");
								jedisShardInfos.add(jedisShardInfo);
							}
							shardedJedisPool = new ShardedJedisPool(config, jedisShardInfos);
							logger.info(">>>>>>>>>>> xxl-sso, JedisUtil.ShardedJedisPool init success.");
						}

					} finally {
						INSTANCE_INIT_LOCL.unlock();
					}
                }

			} catch (InterruptedException e) {
				logger.error(e.getMessage(), e);
			}
		}

		if (shardedJedisPool == null) {
			throw new NullPointerException(">>>>>>>>>>> xxl-sso, JedisUtil.ShardedJedisPool is null.");
		}

		ShardedJedis shardedJedis = shardedJedisPool.getResource();
		return shardedJedis;
	}

	// ------------------------ serialize and unserialize ------------------------
	/**
	 *    -->byte[] (  jedis        object     byte[]  )
	 *
	 * @param object
	 * @return
	 */
	private static byte[] serialize(Object object) {
		ObjectOutputStream oos = null;
		ByteArrayOutputStream baos = null;
		try {
			//    
			baos = new ByteArrayOutputStream();
			oos = new ObjectOutputStream(baos);
			oos.writeObject(object);
			byte[] bytes = baos.toByteArray();
			return bytes;
		} catch (Exception e) {
			logger.error("{}", e);
		} finally {
			try {
				oos.close();
				baos.close();
			} catch (IOException e) {
				logger.error("{}", e);
			}
		}
		return null;
	}

	/**
	 *  byte[] -->Object
	 *
	 * @param bytes
	 * @return
	 */
	private static Object unserialize(byte[] bytes) {
		ByteArrayInputStream bais = null;
		try {
			//     
			bais = new ByteArrayInputStream(bytes);
			ObjectInputStream ois = new ObjectInputStream(bais);
			return ois.readObject();
		} catch (Exception e) {
			logger.error("{}", e);
		} finally {
			try {
				bais.close();
			} catch (IOException e) {
				logger.error("{}", e);
			}
		}
		return null;
	}

	// ------------------------ jedis util ------------------------
	/**
	 *            Object   jedis        Object   ,           
	 *                          ,              ,
	 *             ,  redis                         
	 */

	/**
	 * Set String
	 * @param key
	 * @param value
	 * @param seconds	    ,  / 
	 * @return
	 */
	public static String setStringValue(String key, String value, int seconds) {
		String result = null;
		ShardedJedis client = getInstance();
		try {
			result = client.setex(key, seconds, value);
		} catch (Exception e) {
			logger.info("{}", e);
		} finally {
			client.close();
		}
		return result;
	}

	/**
	 * Set String (      , 2H)
	 * @param key
	 * @param value
	 * @return
	 */
	public static String setStringValue(String key, String value) {
		return setStringValue(key, value, DEFAULT_EXPIRE_TIME);
	}

	/**
	 * Set Object
	 *
	 * @param key
	 * @param obj
	 * @param seconds	    ,  / 
	 */
	public static String setObjectValue(String key, Object obj, int seconds) {
		String result = null;
		ShardedJedis client = getInstance();
		try {
			result = client.setex(key.getBytes(), seconds, serialize(obj));
		} catch (Exception e) {
			logger.info("{}", e);
		} finally {
			client.close();
		}
		return result;
	}

	/**
	 * Set Object (      , 2H)
	 * @param key
	 * @param obj
	 * @return
	 */
	public static String setObjectValue(String key, Object obj) {
		return setObjectValue(key, obj, DEFAULT_EXPIRE_TIME);
	}

	/**
	 * Get String
	 * @param key
	 * @return
	 */
	public static String getStringValue(String key) {
		String value = null;
		ShardedJedis client = getInstance();
		try {
			value = client.get(key);
		} catch (Exception e) {
			logger.info("", e);
		} finally {
			client.close();
		}
		return value;
	}

	/**
	 * Get Object
	 * @param key
	 * @return
	 */
	public static Object getObjectValue(String key) {
		Object obj = null;
		ShardedJedis client = getInstance();
		try {
			byte[] bytes = client.get(key.getBytes());
			if (bytes != null && bytes.length > 0) {
				obj = unserialize(bytes);
			}
		} catch (Exception e) {
			logger.info("", e);
		} finally {
			client.close();
		}
		return obj;
	}

	/**
	 * Delete
	 * @param key
	 * @return Integer reply, specifically:
	 * 		an integer greater than 0 if one or more keys were removed
	 *      0 if none of the specified key existed
	 */
	public static Long del(String key) {
		Long result = null;
		ShardedJedis client = getInstance();
		try {
			result = client.del(key);
		} catch (Exception e) {
			logger.info("{}", e);
		} finally {
			client.close();
		}
		return result;
	}

	/**
	 * incrBy	value  i
	 * @param key
	 * @param i
	 * @return new value after incr
	 */
	public static Long incrBy(String key, int i) {
		Long result = null;
		ShardedJedis client = getInstance();
		try {
			result = client.incrBy(key, i);
		} catch (Exception e) {
			logger.info("{}", e);
		} finally {
			client.close();
		}
		return result;
	}

	/**
	 * exists
	 * @param key
	 * @return Boolean reply, true if the key exists, otherwise false
	 */
	public static boolean exists(String key) {
		Boolean result = null;
		ShardedJedis client = getInstance();
		try {
			result = client.exists(key);
		} catch (Exception e) {
			logger.info("{}", e);
		} finally {
			client.close();
		}
		return result;
	}

	/**
	 * expire	      
	 * @param key
	 * @param seconds	    ,  / 
	 * @return Integer reply, specifically:
	 * 		1: the timeout was set.
	 * 		0: the timeout was not set since the key already has an associated timeout (versions lt 2.1.3), or the key does not exist.
	 */
	public static long expire(String key, int seconds) {
		Long result = null;
		ShardedJedis client = getInstance();
		try {
			result = client.expire(key, seconds);
		} catch (Exception e) {
			logger.info("{}", e);
		} finally {
			client.close();
		}
		return result;
	}

	/**
	 * expireAt		        
	 * @param key
	 * @param unixTime		       
	 * @return
	 */
	public static long expireAt(String key, long unixTime) {
		Long result = null;
		ShardedJedis client = getInstance();
		try {
			result = client.expireAt(key, unixTime);
		} catch (Exception e) {
			logger.info("{}", e);
		} finally {
			client.close();
		}
		return result;
	}

	public static void main(String[] args) {
		init("127.0.0.1:6379");

		setObjectValue("key", "666");
		System.out.println(getObjectValue("key"));
        getInstance();

	}

}
package com.xxl.sso.core.util;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Cookie.Util
 *
 */
public class CookieUtil {

	//       ,  / , 2H
	private static final int COOKIE_MAX_AGE = 60 * 60 * 2;
	//     ,   
	private static final String COOKIE_PATH = "/";
	
	/**
	 *   
	 *
	 * @param response
	 * @param key
	 * @param value
	 * @param ifRemember 
	 */
	public static void set(HttpServletResponse response, String key, String value, boolean ifRemember) {
		int age = ifRemember?COOKIE_MAX_AGE:-1;
		set(response, key, value, null, COOKIE_PATH, age, true);
	}

	/**
	 *   
	 *
	 * @param response
	 * @param key
	 * @param value
	 * @param maxAge
	 */
	private static void set(HttpServletResponse response, String key, String value, String domain, String path, int maxAge, boolean isHttpOnly) {
		Cookie cookie = new Cookie(key, value);
		if (domain != null) {
			cookie.setDomain(domain);
		}
		cookie.setPath(path);
		cookie.setMaxAge(maxAge);
		cookie.setHttpOnly(isHttpOnly);
		response.addCookie(cookie);
	}
	
	/**
	 *   value
	 *
	 * @param request
	 * @param key
	 * @return
	 */
	public static String getValue(HttpServletRequest request, String key) {
		Cookie cookie = get(request, key);
		if (cookie != null) {
			return cookie.getValue();
		}
		return null;
	}

	/**
	 *   Cookie
	 *
	 * @param request
	 * @param key
	 */
	private static Cookie get(HttpServletRequest request, String key) {
		Cookie[] arr_cookie = request.getCookies();
		if (arr_cookie != null && arr_cookie.length > 0) {
			for (Cookie cookie : arr_cookie) {
				if (cookie.getName().equals(key)) {
					return cookie;
				}
			}
		}
		return null;
	}
	
	/**
	 *   Cookie
	 *
	 * @param request
	 * @param response
	 * @param key
	 */
	public static void remove(HttpServletRequest request, HttpServletResponse response, String key) {
		Cookie cookie = get(request, key);
		if (cookie != null) {
			set(response, key, "", null, COOKIE_PATH, 0, true);
		}
	}

}
ユーザが再度ログインした場合、先行メソッドでユーザがログインしたかどうかを確認する.
    public static XxlUser get(String sessionId) {
        String redisKey = redisKey(sessionId);//  sessionid redis   ,          
        Object objectValue = JedisUtil.getObjectValue(redisKey);
        if (objectValue != null) {
            XxlUser xxlUser = (XxlUser) objectValue;
            return xxlUser;
        }
        return null;
    }

大まかな考え方はそうですが、プロジェクトには改善すべき点がたくさんあります.初めて書くのはよくありません.
原作者のgithubアドレスを添付:プロジェクトアドレス