session共享

多台tomcat 集群的时候 要么ip访问固定指向服务器 要么就只能共享session了
集群 

 upstream web_tomcats {
        ip_hash;// ip访问固定指向服务器
server 127.0.0.1:7201 weight=10;
server 127.0.0.1:7202 weight=10;
 
这里 讲共享session  
我们用redis    启动server   ./src/redis-server redis.conf
 redis.conf设置下密码  别让谁都能来玩 
找到# requirepass 去掉#号 requirepass 后面设置密码
可以启动cli 测试一下
./src/redis-cli 不输入密码
./src/redis-cli -a mima 和输入密码
测试语句  set chen haha

然后spring 配置
<!--jedis pool配置 -->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxActive" value="10" />
<property name="maxIdle" value="5" />
<property name="maxWait" value="10" />
<property name="testOnBorrow" value="true" />
</bean>
<!-- jedis pool配置 -->
<bean id="jedisPool" class="redis.clients.jedis.JedisPool">
<constructor-arg index="0" ref="jedisPoolConfig" />
<constructor-arg index="1" value="${Jedis.url}" /> 这个就是ip地址  不要输入http://什么的
<constructor-arg index="2" value="6379" /> 这个是端口号
<constructor-arg index="3" value="3000" /> 这个我也不知道
<constructor-arg index="4" value="${Jedis.pwd}" />
</bean>

pom.xml配置  导个包
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.0.0</version>
    <type>jar</type>
    <scope>compile</scope>
</dependency> 
然后写个redis的 service封装一些方法  这里的封装来源宋哥 哈哈

import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.exceptions.JedisConnectionException;
import redis.clients.jedis.exceptions.JedisException;

/**
 * Redis封装模板及通用方法; 
 * /usr/local/bin/redis-server /etc/redis/6380.conf
 * @author wei
 * 
 */
@Service
public class RedisCacheService {
  Logger logger = Logger.getLogger(RedisCacheService.class);
  
  /**
   * 数据源
   */
  @Autowired private JedisPool jedisPool;

  /**
   * 获取自增id,正整数long 用于jpushsendNo. 
   * 改用redis自身DB支持,不访问数据库
   * 
   * @param  name   业务id, 目前可以使用"jpush","chat_room"
   * @return long 
   */
  public synchronized long getUniqNoSequency(String name){
    return  incr(name + "sequency");
  }


  /**
   *  用户未读信息计数(消息、分享。。一切推送的消息)
   * @param userId 
   * @param reset  清零标记, ture-归零;  默认false
   * @return  0--n  
   */
  public long getMessageCounter(long userId,boolean reset){
    String key= "unreadMessage-"+userId;
    //获取缓存里面的数据
    if(reset){
      del(key);
      return 0;
    }else {
      Long incr = incr(key);
      return incr==null ? 0 : incr;
    }
  }
  

  /******************  下面开始是模板方法! 上面定义公共函数  ***************************************************/  
  
  /**
   * 执行有返回结果的action。
   */
  protected <T> T execute(JedisAction<T> jedisAction) throws JedisException {
    Jedis jedis = null;
    boolean broken = false;
    try {
      jedis = jedisPool.getResource();
      return jedisAction.action(jedis);
    } catch (JedisConnectionException e) {
      logger.error("Redis connection lost.", e);
      broken = true;
      throw e;
    } finally {
      closeResource(jedis, broken);
    }
  }

  /**
   * 执行无返回结果的action。
   */
  protected void execute(JedisActionNoResult jedisAction) throws JedisException {
    Jedis jedis = null;
    boolean broken = false;
    try {
      jedis = jedisPool.getResource();
      jedisAction.action(jedis);
    } catch (JedisConnectionException e) {
      logger.error("Redis connection lost.", e);
      broken = true;
      throw e;
    } finally {
      closeResource(jedis, broken);
    }
  }

  /**
   * 根据连接是否已中断的标志,分别调用returnBrokenResource或returnResource。
   */
  protected void closeResource(Jedis jedis, boolean connectionBroken) {
    if (jedis != null) {
      try {
        if (connectionBroken) {
          jedisPool.returnBrokenResource(jedis);
        } else {
          jedisPool.returnResource(jedis);
        }
      } catch (Exception e) {
        logger.error("Error happen when return jedis to pool, try to close it directly.", e);
        closeJedis(jedis);
      }
    }
  }

  /**
   * 获取内部的pool做进一步的动作。
   */
  public JedisPool getJedisPool() {
    return jedisPool;
  }

  /**
   * 有返回结果的回调接口定义。
   */
  public interface JedisAction<T> {
    T action(Jedis jedis);
  }

  /**
   * 无返回结果的回调接口定义。
   */
  public interface JedisActionNoResult {
    void action(Jedis jedis);
  }

  // ////////////// 常用方法的封装 ///////////////////////// //

  // ////////////// 公共 ///////////////////////////
  /**
   * 删除key, 如果key存在返回true, 否则返回false。
   */
  public boolean del(final String key) {
    return execute(new JedisAction<Boolean>() {

      @Override
      public Boolean action(Jedis jedis) {
        return jedis.del(key) == 1 ? true : false;
      }
    });
  }

  public void flushDB() {
    execute(new JedisActionNoResult() {

      @Override
      public void action(Jedis jedis) {
        jedis.flushDB();
      }
    });
  }

  // ////////////// 关于String ///////////////////////////
  /**
   * 如果key不存在, 返回null.
   */
  public String get(final String key) {
    return execute(new JedisAction<String>() {

      @Override
      public String action(Jedis jedis) {
        return jedis.get(key);
      }
    });
  }

  /**
   * 如果key不存在, 返回0.
   */
  public Long getAsLong(final String key) {
    String result = get(key);
    return result != null ? Long.valueOf(result) : 0;
  }

  /**
   * 如果key不存在, 返回0.
   */
  public Integer getAsInt(final String key) {
    String result = get(key);
    return result != null ? Integer.valueOf(result) : 0;
  }

  public void set(final String key, final String value) {
    execute(new JedisActionNoResult() {

      @Override
      public void action(Jedis jedis) {
        jedis.set(key, value);
      }
    });
  }

  public void setex(final String key, final int seconds, final String value) {
    execute(new JedisActionNoResult() {

      @Override
      public void action(Jedis jedis) {
        jedis.setex(key, seconds, value);
      }
    });
  }

  /**
   * 如果key还不存在则进行设置,返回true,否则返回false.
   */
  public boolean setnx(final String key, final String value) {
    return execute(new JedisAction<Boolean>() {

      @Override
      public Boolean action(Jedis jedis) {
        return jedis.setnx(key, value) == 1 ? true : false;
      }
    });
  }

  public Long incr(final String key) {
    return execute(new JedisAction<Long>() {

      @Override
      public Long action(Jedis jedis) {
        return jedis.incr(key);
      }
    });
  }

  public Long decr(final String key) {
    return execute(new JedisAction<Long>() {

      @Override
      public Long action(Jedis jedis) {
        return jedis.decr(key);
      }
    });
  }

  // ////////////// 关于List ///////////////////////////
  public void lpush(final String key, final String value) {
    execute(new JedisActionNoResult() {

      @Override
      public void action(Jedis jedis) {
        jedis.lpush(key, value);
      }
    });
  }

  /**
     * Return the length of the list stored at the specified key. If the key
     * does not exist zero is returned (the same behaviour as for empty lists).
     * If the value stored at key is not a list an error is returned.
   */
  public long llen(final String key) {
    return execute(new JedisAction<Long>() {

      @Override
      public Long action(Jedis jedis) {
        return jedis.llen(key);
      }
    });
  }

  /**
   * 删除List中的第一个等于value的元素,value不存在或key不存在时返回0.
   */
  public boolean lremOne(final String key, final String value) {
    return execute(new JedisAction<Boolean>() {
      @Override
      public Boolean action(Jedis jedis) {
        Long count = jedis.lrem(key, 1, value);
        return (count == 1);
      }
    });
  }

  /**
     * Return the specified elements of the list stored at the specified key.
     * Start and end are zero-based indexes. 0 is the first element of the list
     * (the list head), 1 the next element and so on.
   */
  public List<String> lrange(final String key, final long start, final long end) {
    return execute(new JedisAction<List<String>>() {
      @Override
      public List<String> action(Jedis jedis) {
        return jedis.lrange(key, start, end);
      }
    });

  }

  /**
   * 删除List中的所有等于value的元素,value不存在或key不存在时返回0.
   */
  public boolean lremAll(final String key, final String value) {
    return execute(new JedisAction<Boolean>() {
      @Override
      public Boolean action(Jedis jedis) {
        Long count = jedis.lrem(key, 0, value);
        return (count > 0);
      }
    });
  } 
  
  
  // ////////////// 关于Sorted Set ///////////////////////////
  /**
   * 加入Sorted set, 如果member在Set里已存在,只更新score并返回false,否则返回true.
   */
  public boolean zadd(final String key, final String member, final double score) {
    return execute(new JedisAction<Boolean>() {

      @Override
      public Boolean action(Jedis jedis) {
        return jedis.zadd(key, score, member) == 1 ? true : false;
      }
    });
  }

  /**
   * 删除sorted set中的元素,成功删除返回true,key或member不存在返回false。
   */
  public boolean zrem(final String key, final String member) {
    return execute(new JedisAction<Boolean>() {

      @Override
      public Boolean action(Jedis jedis) {
        return jedis.zrem(key, member) == 1 ? true : false;
      }
    });
  }

  /**
   * 返回List长度, key不存在时返回0,key类型不是sorted set时抛出异常.
   */
  public long zcard(final String key) {
    return execute(new JedisAction<Long>() {

      @Override
      public Long action(Jedis jedis) {
        return jedis.zcard(key);
      }
    });
  }

  /**
   * Set a timeout on the specified key
   * @param key
   * @param seconds
   */
  public void expire(final String key, final int seconds) {
    execute(new JedisActionNoResult() {
      @Override
      public void action(Jedis jedis) {
        jedis.expire(key, seconds);
      }
    });
  }
  
  public boolean exists(final String key) {
    return execute(new JedisAction<Boolean>() {
      @Override
      public Boolean action(Jedis jedis) {
        return jedis.exists(key);
      }
    });
  }
  
  
  /**
   * 退出然后关闭Jedis连接。
   */
  public static void closeJedis(Jedis jedis) {
    if (jedis.isConnected()) {
      try {
        try {
          jedis.quit();
        } catch (Exception e) {
        }
        jedis.disconnect();
      } catch (Exception e) {

      }
    }
  } 

}

最后就是一些思路上的问题了
  用户登录 发送请求 登录成功 生成一个32位的MD5字符戳 和用户对象 User
把他当做key value存在redis里面 User弄成json字符串  
比如说 

redisCacheService.setex(sessionid, 60*120, new Gson().toJson(user)); //
60*120这个是60秒*120  120分钟啦

String cache= redisCacheService.get(token);
 user=new Gson().fromJson(cache, User.class); 

生成的 MD5字符串传回给用户   浏览器存到cookie里面去  每个请求都会自动带cookie来的 嘿嘿 
每次取cache不为null的时候 就再写入一遍  不然过期了 你负责啊
然后基本就成功了




【直流微电网】径向直流微电网的状态空间建模与线性化:一种耦合DC-DC变换器状态空间平均模型的方法 (Matlab代码实现)内容概要:本文介绍了径向直流微电网的状态空间建模与线性化方法,重点提出了一种基于耦合DC-DC变换器状态空间平均模型的建模策略。该方法通过对系统中多个相互耦合的DC-DC变换器进行统一建模,构建出整个微电网的集中状态空间模型,并在此基础上实施线性化处理,便于后续的小信号分析与稳定性研究。文中详细阐述了建模过程中的关键步骤,包括电路拓扑分析、状态变量选取、平均化处理以及雅可比矩阵的推导,最终通过Matlab代码实现模型仿真验证,展示了该方法在动态响应分析和控制器设计中的有效性。; 适合人群:具备电力电子、自动控制理论基础,熟悉Matlab/Simulink仿真工具,从事微电网、新能源系统建模与控制研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①掌握直流微电网中多变换器系统的统一建模方法;②理解状态空间平均法在非线性电力电子系统中的应用;③实现系统线性化并用于稳定性分析与控制器设计;④通过Matlab代码复现和扩展模型,服务于科研仿真与教学实践。; 阅读建议:建议读者结合Matlab代码逐步理解建模流程,重点关注状态变量的选择与平均化处理的数学推导,同时可尝试修改系统参数或拓扑结构以加深对模型通用性和适应性的理解。
<think>嗯,用户想了解如何在不同环境或应用中实现Session共享,特别是跨域的解决方案。我之前整理过几个引用,里面提到了Cookie的Domain设置、自定义Session ID、集中存储这些方法。需要先理清楚这些方法的适用场景和步骤。 首先,Cookie的Domain属性设置,比如将Domain设为.example.com,这样所有子域都能共享Session。但用户可能还涉及完全不同的域,这时候可能需要其他方法。比如引用3里提到自定义Session ID,存储在服务端,如数据库或Redis,这样不同的域都能通过这个ID来获取Session数据。然后,集中存储方案,比如Redis或数据库,这适用于不同服务器之间共享Session。需要确保所有应用服务器都连接同一个存储,这样无论请求到哪台服务器,都能访问到相同的Session数据。这可能和负载均衡有关,比如引用里提到的Nginx配置,但用户的问题更偏向Session共享而不是负载均衡。还有SSO单点登录,这属于更高级的解决方案,可能涉及独立的认证中心,比如OAuth或JWT。这时候每个应用向认证中心验证token,实现跨域登录。这可能适合用户提到的不同应用间的共享,但需要更复杂的设置。 另外,用户可能关心的是具体实现步骤,比如代码示例。例如PHP设置Cookie的Domain,或者Java中配置SpringSession使用Redis。需要分点说明不同的方法,并给出对应的技术实现,比如代码片段或配置示例。 还要注意安全性,比如Cookie的Secure和HttpOnly属性,SameSite设置,防止CSRF攻击。引用里提到Secure:true和SameSite: None,这些在HTTPS下是必要的。可能还需要比较这些方法的优缺点。比如Cookie跨子域简单,但无法跨完全不同的域;集中存储需要基础设施支持;SSO适合大型系统但实现复杂。用户可能需要根据他们的具体场景选择合适的方法。最后,生成相关问题,帮助用户进一步探索。比如如何确保Session共享的安全性,或者微服务架构下的Session管理。这些问题可以引导用户深入思考他们的需求。</think>### 跨域Session共享解决方案 #### 一、基于Cookie的跨域共享(同主域场景) 1. **适用场景** 系统运行在相同主域下的子域(如`a.example.com`和`b.example.com`),通过设置Cookie的`Domain`属性实现共享: ```go http.SetCookie(w, &http.Cookie{ Name: "SESSION_ID", Value: "your-session-id", Domain: ".example.com", // 允许所有子域共享 Path: "/", HttpOnly: true, Secure: true, // 仅HTTPS生效 SameSite: http.SameSiteNoneMode, }) ``` - **原理**:浏览器会自动将Cookie发送到匹配域名的请求中[^1][^2]。 - **限制**:仅适用于同一主域下的跨子域场景。 --- #### 二、自定义Session ID + 集中存储(跨域通用) 1. **实现步骤** - **生成全局Session ID**:用户登录时生成唯一标识(如UUID),存入跨域Cookie。 - **集中存储Session数据**:将数据保存到Redis或数据库,例如: ```php setcookie("session_idx", $session_id, time()+3600*24*365*10, "/", ".example.com"); Redis::set("session:$session_id", serialize($user_data)); ``` - **跨域验证**:不同域的应用通过Session ID查询集中存储获取用户状态[^3][^4]。 2. **技术选型** - **存储层**:Redis(高性能)、MySQL(强一致性)。 - **框架支持**:Spring Session(Java)、Flask-Session(Python)。 --- #### 三、基于Token的无状态方案(完全跨域) 1. **JWT(JSON Web Token)** - **流程**:用户登录后返回加密Token,包含用户信息,由客户端存储并在跨域请求中携带。 - **示例Token结构**: ```json { "sub": "user123", "exp": 1625145600, "domain_a": "read", "domain_b": "write" } ``` - **优点**:无需服务端存储Session,天然支持跨域[^3]。 --- #### 四、反向代理统一域名(简化跨域) 1. **Nginx配置** 通过反向代理将不同域名的请求映射到统一入口: ```nginx server { server_name sso.example.com; location / { proxy_pass http://backend-server; proxy_set_header Host $host; } } ``` - **效果**:所有应用通过`sso.example.com`共享Session,规避浏览器跨域限制。 --- #### 五、单点登录(SSO)系统 1. **核心组件** - **认证中心**:独立服务处理登录/注销。 - **Ticket验证**:通过重定向传递临时票据(如CAS协议)。 - **跨域Cookie联动**:使用隐藏iframe或前端存储同步登录状态。 --- ### 对比分析 | 方案 | 适用场景 | 复杂度 | 安全性要求 | |---------------------|--------------------------|--------|--------------------| | Cookie Domain | 同主域的子域 | 低 | 中(需HTTPS) | | 集中存储 + Session ID | 任意跨域 | 中 | 高(需加密存储) | | JWT | 无状态API跨域 | 中 | 高(密钥管理) | | SSO | 多系统统一认证 | 高 | 极高(防重放攻击) | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值