通过cookie+Redis解决tomcat集群后的登录问题

            Tomcat+nginx集群后,登录的问题就暴露了出来,通过nginx负载均衡后,用户第一次访问转发到TomcatA上,用户登录之后,在此访问又转发到TomcatB上,而TomcatB上并没有用户登录的session信息,所以又一次提示用户需要登录,本次通过cookie+Redis实现单点登录解决Tomcat集群后带来的登录问题。

Tomcat+nginx集群配置:https://blog.csdn.net/qq_37585236/article/details/81590588

Redis安装;https://blog.csdn.net/qq_37585236/article/details/81460046

POM依赖:

<!--jedis-->
<dependency>
  <groupId>redis.clients</groupId>
  <artifactId>jedis</artifactId>
  <version>2.6.0</version>
</dependency>

获取properties配置文件值:

import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Properties;

/**
 * Created by geely
 */
@Slf4j
public class PropertiesUtil {

    private static Properties prop;

    static {
        String fileName = "properties配置文件";
        prop = new Properties();
        try {
            //加载Properties
            prop.load(new InputStreamReader(PropertiesUtil.class.getClassLoader().getResourceAsStream(fileName), "UTF-8"));
        } catch (IOException e) {
            log.error("初始化配置失败", e);
        }
    }

    public static String getKey(String key) {
        String value = prop.getProperty(key.trim());
        if (value == null) {
            return null;
        }
        return value.trim();
    }

    public static String getKey(String key, String defaultValue) {
        String value = prop.getProperty(key.trim());
        if (value == null) {
            return defaultValue;
        }
        return value.trim();
    }


}

一.     封装jedis连接池、jedisApi

jedis连接池:

import com.mmall.util.PropertiesUtil;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPoolConfig;

/**
 * @author Luyue
 * @date 2018/8/11 14:29
 **/
public class JedisPool {
    private static redis.clients.jedis.JedisPool pool;

    //redis ip 地址
    private static String ip = PropertiesUtil.getKey("redis2.ip");
    //redis 端口号
    private static Integer port = Integer.parseInt(PropertiesUtil.getKey("redis2.port", "6379"));

    //最大连接数
    private static Integer maxTotal = Integer.parseInt(PropertiesUtil.getKey("redis.max.total", "20"));
    //最大空闲连接数
    private static Integer maxIdle = Integer.parseInt(PropertiesUtil.getKey("redis.max.idle", "10"));
    //最小空闲连接数
    private static Integer minIdle = Integer.parseInt(PropertiesUtil.getKey("redis.min.idle", "2"));

    //通过连接池拿去jedis连接时,校验并返回可用连接
    private static Boolean testOnBorrow = Boolean.parseBoolean(PropertiesUtil.getKey("redis.test.borrow", "true"));
    //通过连接池返还jedis连接时,校验该连接
    private static Boolean testOnReturn = Boolean.parseBoolean(PropertiesUtil.getKey("redis.test.return", "true"));

    /**
     * 初始化连接池
     */
    private static void initPool() {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();

        jedisPoolConfig.setMaxTotal(maxTotal);
        jedisPoolConfig.setMaxIdle(maxIdle);
        jedisPoolConfig.setMinIdle(minIdle);
        jedisPoolConfig.setTestOnBorrow(testOnBorrow);
        jedisPoolConfig.setTestOnReturn(testOnReturn);

        //当连接池无空闲连接时,是否阻塞
        jedisPoolConfig.setBlockWhenExhausted(true);

        pool = new redis.clients.jedis.JedisPool(jedisPoolConfig, ip, port, 1000*2);
    }

    static {
        initPool();
    }

    /**
     * 获取一个连接
     * @return
     */
    public static Jedis getJedis() {
        return pool.getResource();
    }

    /**
     * 返还错误的连接
     * @param jedis
     */
    public static void returnBrokenJedis(Jedis jedis) {
        pool.returnBrokenResource(jedis);
    }

    /**
     * 返还连接
     * @param jedis
     */
    public static void returnJedis(Jedis jedis) {
        pool.returnResource(jedis);
    }
}

jedisApi:

import com.mmall.common.JedisPool;
import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.Jedis;

/**
 * @author Luyue
 * @date 2018/8/11 14:29
 **/
@Slf4j
public class JedisPoolUtil {

    /**
     * 存储键值
     * @param key
     * @param value
     * @return
     */
    public static String set(String key, String value) {
        Jedis jedis = null;
        String response = null;

        try {
            jedis = JedisPool.getJedis();
            response = jedis.set(key, value);
        } catch (Exception e) {
            log.error("set key:{}, value:{} is error:{}", key, value, e);
            JedisPool.returnBrokenJedis(jedis);
            return response;
        }

        JedisPool.returnJedis(jedis);
        return response;
    }

    /**
     * 存储键值,并设置有效时间
     * @param key
     * @param value
     * @param exTime
     * @return
     */
    public static String setEx(String key, String value, int exTime) {
        Jedis jedis = null;
        String response = null;

        try {
            jedis = JedisPool.getJedis();
            response = jedis.setex(key, exTime, value);
        } catch (Exception e) {
            log.error("setEx key:{}, value:{} is error:{}", key, value, e);
            JedisPool.returnBrokenJedis(jedis);
            return response;
        }

        JedisPool.returnJedis(jedis);
        return response;
    }

    /**
     * 获取value
     * @param key
     * @return
     */
    public static String get(String key) {
        Jedis jedis = null;
        String response = null;

        try {
            jedis = JedisPool.getJedis();
            response = jedis.get(key);
        } catch (Exception e) {
            log.error("get key:{}, is error:{}", key, e);
            JedisPool.returnBrokenJedis(jedis);
            return response;
        }

        JedisPool.returnJedis(jedis);
        return response;
    }

    /**
     * 设置键的有效时间
     * @param key
     * @param exTime
     * @return
     */
    public static Long expire(String key, int exTime) {
        Jedis jedis = null;
        Long response = null;

        try {
            jedis = JedisPool.getJedis();
            response = jedis.expire(key, exTime);
        } catch (Exception e) {
            log.error("expire key:{}, is error:{}", key, e);
            JedisPool.returnBrokenJedis(jedis);
            return response;
        }

        JedisPool.returnJedis(jedis);
        return response;
    }

    /**
     * 删除键
     * @param key
     * @return
     */
    public static Long del(String key) {
        Jedis jedis = null;
        Long response = null;

        try {
            jedis = JedisPool.getJedis();
            response = jedis.del(key);
        } catch (Exception e) {
            log.error("del key:{}, is error:{}", key, e);
            JedisPool.returnBrokenJedis(jedis);
            return response;
        }

        JedisPool.returnJedis(jedis);
        return response;
    }
}

二.封装cookieAPI

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

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

/**
 * @author Luyue
 * @date 2018/8/12 14:40
 **/
@Slf4j
public class CookieUtil {

    /**
     *tomcat 8.5的用法,tomcat8.5以下:.luyue.com
     */
    private static final String COOKIE_DOMAIN = "luyue.com";
    private static final String COOKIE_NAME = "login_token";

    /**
     * 种入cookie
     * @param token
     * @param response
     */
    public static void writeCookie(String token, HttpServletResponse response) {
        Cookie cookie = new Cookie(COOKIE_NAME, token);
        cookie.setDomain(COOKIE_DOMAIN);
        cookie.setPath("/");
        //如果设置-1 , 代表cookie 永久有效
        cookie.setMaxAge(60 * 60 * 24 * 365);
        cookie.setHttpOnly(true);

        log.info("write cookie name:{} value:{}", cookie.getName(), cookie.getValue());

        response.addCookie(cookie);
    }

    /**
     * 获取cookie
     * @param request
     * @return
     */
    public static String readCookie(HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        if (cookies == null) {
            return null;
        }

        for (Cookie c : cookies) {
            if (StringUtils.equals(c.getName(), COOKIE_NAME)) {
                log.info("read cookie name:{} value:{}", c.getName(), c.getValue());
                return c.getValue();
            }
        }

        return null;
    }

    /**
     * 删除cookie
     * @param request
     * @param response
     */
    public static void delCookie(HttpServletRequest request, HttpServletResponse response) {
        Cookie[] cookies = request.getCookies();

        if (cookies != null) {
            for (Cookie c: cookies) {
                if (StringUtils.equals(c.getName(), COOKIE_NAME)) {
                    log.info("del cookie name:{} value:{}", c.getName(), c.getValue());
                    c.setDomain(COOKIE_DOMAIN);
                    c.setPath("/");
                    c.setMaxAge(0);

                    response.addCookie(c);
                    break;
                }
            }
        }
    }
}

三.登录例子

public ServerResponse<User> login(String username, String password, HttpSession session, HttpServletResponse servletResponse) {
    ServerResponse<User> response = iUserService.login(username, password);
    //校验用户名密码
    if (response.isSuccess()) {
        //Redis的key值存储在cookie中,这样每次判断用户是否登录只需要从cookie中获取key值,在从Redis取得user就行
        CookieUtil.writeCookie(session.getId(), servletResponse);
        //将登录用户的信息存储到Redis中
        JedisPoolUtil.setEx(session.getId(), JsonUtil.objToJson(response.getData()), Constants.RedisExTime.EX_TIME);
    }
    return response;
}

这样,每次判断用户是否登录,只需判断cookie中是否有相关token,没有则表示没有登录,有则继续判断Redis中是否可以取得value:

public ServerResponse<User> getUserInfo(HttpServletRequest request) {
    String token = CookieUtil.readCookie(request);
    User user = JsonUtil.json2Object(ShardedJedisPoolUtil.get(token), User.class);
    if (user == null) {
        return ServerResponse.createByErrorMessage("请登录");
    }
    return ServerResponse.createBySuccess(user);
}

猜你喜欢

转载自blog.csdn.net/qq_37585236/article/details/81747711