DBMNG数据库管理与应用

书籍是全世界的营养品。生活里没有书籍,就好像没有阳光;智慧里没有书籍,就好像鸟儿没有翅膀。
当前位置:首页 > 经验分享 > Java开发

分布式应用session会话管理-基于redis

session会话在单台服务器下不会出现共享问题,现在应用部署方式都是分布式,或者集群部署,这样必然会面临一个问题,session共享。




session共享的解决方案也有很多,




一、web服务器的粘性请求,比如采用nginx请求分发,使用ip_hash这种负载均衡方式,客户端请求只会被分发到相同的后台server,这样可以避免session共享的问题。但是缺点也很明显


二、基于数据库存储(网站用户量大的情况下,频繁dml数据,对db压力大)


三、基于cookie存储(安全问题、虽然可以加密存储、但是我觉得永远不能将敏感数据放在客户端,不信任啊O(∩_∩)O哈哈~)


四、服务器内置的session复制域(比如was下提供session复制功能、但这个损耗服务器内存)


五、基于nosql(memcache、redis都可以)





http请求是无状态的


这里要引入一个概念sessionid,session对象当客户端首次访问时,创建一个新的session对象.并同时生成一个sessionId,并在此次响应中将sessionId以响应报文的方式些回客户端浏览器内存或以重写url方式送回客户端,来保持整个会话


也就是说客户端request请求时候,如果获取了session,就默认分配一个jessionid,然后通过response响应到客户端cookie,然后客户端下一次请求,默认会携带这个jessionid请求到服务端,服务端拿到这个jessionid来区分不同的客户端。




说清楚这些,就可以从sessionid入手了,要实现将session信息存入redis,总结了下大概是三点:


1.实现httpsession接口,重写我们需要用到的方法,比如set get这些。。balabala一堆......


2.继承HttpServletRequestWrapper,这个类里面有getSession()方法,我们需要重写,来取自定义session


3.实现filter,用来拦截客户端请求,获取我们自定义的request,从而获得session




具体实现:


1.实现httpsession接口


public class HttpSessionWrapper implements HttpSession {

    protected final Logger logger = LoggerFactory.getLogger(getClass());

private String sid = "";

private HttpServletRequest request;

private HttpServletResponse response;

private final long creationTime = System.currentTimeMillis();

private final long lastAccessedTime = System.currentTimeMillis();

private SessionMeta meta;

public HttpSessionWrapper() {

}

    public HttpSessionWrapper(String sid,SessionMeta meta, HttpServletRequest request,

HttpServletResponse response) {

    this.sid=sid;

    this.request=request;

    this.response=response;

    this.meta=meta;

}

public Object getAttribute(String name) {

    logger.info(getClass()+"getAttribute(),name:"+name);

  Jedis jedis =null;

  Object obj =null;

  String jsonStr = null;

    try {

    jedis =JedisPoolStore.getInstance().getJedis(meta.getHost(), meta.getPort());

    jsonStr = jedis.get(name);

        if(jsonStr!=null||StringUtils.isNotEmpty(jsonStr)){

            jedis.expire(name, meta.getSeconds());// 重置过期时间

    obj =JSON.parseObject(jsonStr, User.class); //反序列对象

        }

        if (jedis != null) {

    JedisPoolStore.getInstance().returnJedis(jedis);

    }

        return obj;

    catch (JSONException je) {

logger.error(je.getMessage());

if (null != jedis)

JedisPoolStore.getInstance().returnJedis(jedis);

        return jsonStr;

}

    catch (Exception e) {

logger.error(e.getMessage());

if (e instanceof JedisException) {

if (null != jedis)

JedisPoolStore.getInstance().returnBrokenJedis(jedis);

} else {

if (null != jedis)

JedisPoolStore.getInstance().returnJedis(jedis);

}

throw new HttpSessionException(" session 异常  getAttribute() name:"+name);

}

    }

    public void setAttribute(String name, Object value) {

    logger.info(getClass()+"setAttribute(),name:"+name);

    Jedis jedis =null;

    try {

    jedis =JedisPoolStore.getInstance().getJedis(meta.getHost(), meta.getPort());

    if(value instanceof String){

    String value_ =(String) value;

    jedis.set(name,value_);//普通字符串对象

    }else{

    jedis.set(name, JSON.toJSONString(value));//序列化对象

    }

   

        jedis.expire(name, meta.getSeconds());// 重置过期时间

        if (jedis != null) {

    JedisPoolStore.getInstance().returnJedis(jedis);

    }

} catch (Exception e) {

logger.error(e.getMessage());

if (e instanceof JedisException) {

if (null != jedis)

JedisPoolStore.getInstance().returnBrokenJedis(jedis);

} else {

if (null != jedis)

JedisPoolStore.getInstance().returnJedis(jedis);

}

throw new HttpSessionException(" session 异常  setAttribute() name:"+name+",value:"+value);

}

   

    }

    /**

     * 不可用

     * @deprecated

     * 

     */

    public void invalidate() {

    logger.info(getClass()+"invalidate()");

    }

 

    public void removeAttribute(String name) {

    logger.info(getClass()+"removeAttribute(),name:"+name);

    if(StringUtils.isNotEmpty(name)){

    Jedis jedis =null;

        try {

        jedis =JedisPoolStore.getInstance().getJedis(meta.getHost(), meta.getPort());

            jedis.del(name);

            if (jedis != null) {

        JedisPoolStore.getInstance().returnJedis(jedis);

        }

    } catch (Exception e) {

    logger.error(e.getMessage());

    if (e instanceof JedisException) {

    if (null != jedis)

    JedisPoolStore.getInstance().returnBrokenJedis(jedis);

    } else {

    if (null != jedis)

    JedisPoolStore.getInstance().returnJedis(jedis);

    }

    throw new HttpSessionException(" session 异常  removeAttribute() name:"+name);

    }

    }

    

    }

    /**

     * 不可用

     * @deprecated

     * 

     */

    public Object getValue(String name) {

        return null;

    }

    /**

     * 不可用

     * @deprecated

     * 

     */

    public Enumeration getAttributeNames() {

    return  null;

 

    } 

    /**

     * 不可用

     * @deprecated

     * 

     */

    public String[] getValueNames() {

    return  null;    

}

    /**

     * 不可用

     * @deprecated

     * 

     */

    public void putValue(String name, Object value) {

    }

    /**

     * 不可用

     * @deprecated

     * 

     */

    public void removeValue(String name) {

    }

 

    public long getCreationTime() {

    return  creationTime;

    }

 

    public String getId() {

    logger.info(getClass()+"getId():"+sid);

        return sid;

    }

 

    public long getLastAccessedTime() {

        return lastAccessedTime;

    }

    /**

     * 不可用

     * @deprecated

     * 

     */

    public ServletContext getServletContext() {

        return null;

    }

    /**

     * 不可用

     * @deprecated

     * 

     */

    public void setMaxInactiveInterval(int interval) {

    }

    /**

     * 不可用

     * @deprecated

     * 

     */

    public int getMaxInactiveInterval() {

        return 0;

    }

    /**

     * 不可用

     * @deprecated

     * 

     */

    public HttpSessionContext getSessionContext() {

        return null;

    }

    /**

     * 不可用

     * @deprecated

     * 

     */

    public boolean isNew() {

    logger.info(getClass()+"isNew()");

        return false;

    }

}


2.继承HttpServletRequestWrapper

/***

 * 

 * @author xiaoshuai

 *

 */

public class DefinedHttpServletRequestWrapper extends HttpServletRequestWrapper{

    protected final Logger logger = LoggerFactory.getLogger(getClass());

 

    private HttpSessionWrapper currentSession;

    private HttpServletRequest request;

    private HttpServletResponse response;

    private String sid = "";

private  SessionMeta meta;

     

    public DefinedHttpServletRequestWrapper(HttpServletRequest request) {

        super(request);

    }

 

    public DefinedHttpServletRequestWrapper(String sid, HttpServletRequest request) {

        super(request);

        this.sid = sid;

    }

 

    public DefinedHttpServletRequestWrapper(String sid, SessionMeta meta,HttpServletRequest request,

            HttpServletResponse response) {

        super(request);

        this.request = request;

        this.response = response;

        this.sid = sid;

        this.meta=meta;

    }

 

    @Override

    public HttpSession getSession(boolean create) {

    if(currentSession != null) {

           return currentSession;

         }

         if(!create) {

           return null;

         }

         currentSession = new HttpSessionWrapper(sid,meta, request, response);

         return currentSession;

    }

 

    @Override

    public HttpSession getSession() {

      return getSession(true);

    }

    

}


3.实现filter


public class SessionFilter implements Filter{

protected final Logger logger = LoggerFactory.getLogger(getClass());

private static SessionMeta meta = new SessionMeta();

private static final String host ="host";

private static final String port ="port";

private static final String seconds="seconds";

public void init(FilterConfig filterConfig) throws ServletException {

logger.debug("init filterConfig info");

meta.setHost(filterConfig.getInitParameter(host));

meta.setPort(Integer.parseInt(filterConfig.getInitParameter(port)));

meta.setSeconds(Integer.parseInt(filterConfig.getInitParameter(seconds)));

}

 

public void doFilter(ServletRequest request, ServletResponse response,

FilterChain chain) throws IOException, ServletException {

//从cookie中获取sessionId,如果此次请求没有sessionId,重写为这次请求设置一个sessionId

HttpServletRequest httpRequest = (HttpServletRequest) request;

HttpServletResponse httpResponse = (HttpServletResponse) response;

        String sid = CookieHelper.findCookieInfo(httpRequest,CookieHelper.COOKIE_DOMAIN_NAME);

        if(StringUtils.isEmpty(sid) ){

        try {

        sid =CookieHelper.saveCookie(SessionId.doIds(), httpResponse);

} catch (Exception e) {

e.printStackTrace();

}

        }

        logger.info("JESSIONID:"+sid);

        chain.doFilter(new DefinedHttpServletRequestWrapper(sid,meta,httpRequest, httpResponse), response);

}

 

public void destroy() {

}

 

}



3.配置web.xml



<!-- session过滤器 -->

<filter>

<filter-name>sessionFilter</filter-name>

<filter-class>cn.session.filter.SessionFilter</filter-class>

<init-param>

<param-name>host</param-name>

<param-value>10.1.193.1</param-value>

</init-param>

<init-param>

<param-name>port</param-name>

<param-value>6372</param-value>

</init-param>

<init-param>

<param-name>seconds</param-name>

<param-value>1800</param-value>

</init-param>

</filter>

<filter-mapping>

<filter-name>sessionFilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>






第一次产生sessionid访问:








系统登录后存用户信息至redis,以及产生令牌:










关于安全这块,因为不管登录系统与否,sessionid都会产生,这时候就会产生一个问题,因为cookie是可以被修改的,就会产生一个问题,撞session的分享。。。换成不同的sessionid去请求系统。。。总有一天会撞上。。




SO,我这边是这样处理的:


当登录成功之后,产生一个token令牌,产生规则的话自己定,一堆密钥比如系统名字+sessionid+userid+固定字符,产生一个加密的字符串,放入cookie。


这样当我们获取当前登录用户时,解密token,获取sessionid,然后取redis用户信息。。(切记这里不要直接通过sessionid取用户信息,有风险!!!)


用户没有登录成功,自然也没有这个令牌。。。


https://blog.csdn.net/u010497606/article/details/52935556 


本站文章内容,部分来自于互联网,若侵犯了您的权益,请致邮件chuanghui423#sohu.com(请将#换为@)联系,我们会尽快核实后删除。
Copyright © 2006-2023 DBMNG.COM All Rights Reserved. Powered by DEVSOARTECH            豫ICP备11002312号-2

豫公网安备 41010502002439号