当前位置: 首页 > wzjs >正文

织梦网站字体大小山东菏泽建设银行网站

织梦网站字体大小,山东菏泽建设银行网站,整套vi设计包含哪些,沈阳网站seo公司记录一下因为增加redis账号登录互斥的需求导致的session失效的问题,引发的学习Java 对象引用问题。 问题导火索: 原来登录时直接如下两行即可设置session中的对象参数 SysUserExt user (SysUserExt) subject.getSession().getAttribute(CommonConstan…

记录一下因为增加redis账号登录互斥的需求导致的session失效的问题,引发的学习Java 对象引用问题。

问题导火索:

原来登录时直接如下两行即可设置session中的对象参数

SysUserExt user= (SysUserExt) subject.getSession().getAttribute(CommonConstant.SESSION_USER_KEY);
user.setMenuModels(menuModels);

但是加了登录账号互斥的情况下,如下,会导致上述设置失效

    @Bean(name = "securityManager")public DefaultWebSecurityManager getDefaultWebSecurityManager() {DefaultWebSecurityManager dwsm = new DefaultWebSecurityManager();dwsm.setRealm(getShiroRealm());dwsm.setRememberMeManager(rememberMeManager());dwsm.setSessionManager(sessionManager());return dwsm;}

必须这样去进行修改,才可以在session中拿到值

SysUserExt sysUserEmpExt = (SysUserExt) subject.getSession().getAttribute(CommonConstant.SESSION_USER_KEY);sysUserEmpExt.setMenuModels(menuModels);subject.getSession().setAttribute(CommonConstant.SESSION_USER_KEY, sysUserEmpExt);

发生的原因:

项目使用的是:

RedisSessionDAO(Shiro + Redis)

这就引出了关键点:

🧠 Shiro + RedisSessionDAO 的机制

  • getAttribute(...):从 Redis 中取出 一个反序列化副本

  • 修改这个副本,不会影响 Redis 中存储的 session

  • 除非你 调用 setAttribute(...) 把它重新写回去

  • 🔍 所以:

    ✅ 第一段代码:
    SysUserExt user = (SysUserExt) subject.getSession().getAttribute(...); user.setMenuModels(...);

    只是修改了内存中的一个临时副本,并不会写回 Redis 中的 session


    ✅ 第二段代码:
    SysUserExt sysUserEmpExt = (SysUserExt) subject.getSession().getAttribute(...); 
    sysUserEmpExt.setMenuModels(...); 
    subject.getSession().setAttribute(..., sysUserEmpExt);

    修改了之后重新调用 setAttribute(...),就把这个对象重新写入 Redis 中。

原因解释:

  • 如果你使用的是 Shiro 的默认 ServletContainerSessionManager(也就是用的 servlet 容器自带的 HttpSession,如 Tomcat、Jetty),Servlet 的 session 是 JVM 内存中的对象引用,修改引用内容会立即体现在 session 中。

  • RedisSessionDAO 把对象序列化进 Redis,每次 getAttribute() 都是反序列化一个副本,改了不影响原值,必须重新 setAttribute()


下面 简单的代码示例 + 图示解释思维 来讲清楚 Java 中的对象引用。


✅ 场景一:对象引用指向同一个实例

public class ReferenceDemo {public static void main(String[] args) {Person p1 = new Person("Alice");Person p2 = p1; // p2和p1指向同一个对象p2.setName("Bob");System.out.println(p1.getName()); // 输出结果:Bob}
}
public class Person {private String name;public Person(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}

🎯 解释:

  • p1p2 指向的是同一个内存地址(Person 对象)

  • 所以通过 p2.setName("Bob") 修改后,p1.getName() 看到的是同样的值


🧠 内存图示(堆):

   +---------------------+
   |     Person(name=Bob)|
   +---------------------+
       ↑           ↑
      p1          p2


✅ 场景二:重新赋值引用对象

public class Demo2 {public static void main(String[] args) {Person p1 = new Person("Alice");Person p2 = new Person("Charlie");p2 = p1;  // p2 now references the same object as p1p2.setName("Dave");System.out.println(p1.getName());  // Output: Dave}
}

🎯 解释:

  • 原本 p2 是另一个对象,但 p2 = p1; 后,两个变量都引用同一个对象了

  • 修改一个,另一个也看到变化


❌ 场景三:复制对象不能共享引用

public class Demo3 {public static void main(String[] args) {Person p1 = new Person("Alice");Person p2 = new Person(p1.getName()); // 创建新对象,复制name值p2.setName("Eve");  // 修改p2的nameSystem.out.println(p1.getName());  // p1的name保持原值"Alice"}
}

🎯 解释:

  • 虽然内容一样,但 p1p2 是两个独立的对象,修改一个不会影响另一个


✅ 扩展场景:集合中的引用

List<Person> people = new ArrayList<>();
Person person = new Person("Tom");
people.add(person);
person.setName("Jerry");
System.out.println(people.get(0).getName()); // 输出 Jerry

🎯 解释:

  • list 存的不是 Person 的副本,而是引用

  • 所以即使你在外部修改 p,集合内的对象也会变化


✅ 总结

操作是否引用同一对象修改是否互相影响
Person p2 = p1✅ 是✅ 会
Person p2 = new Person(p1.getName())❌ 否❌ 不会
放入集合中✅ 是引用✅ 会
RedisSessionDAO 反序列化❌ 复制品❌ 不会自动同步

修改后的原代码如下:

一:登录的service:

private UserDTO loginAuthenticate(String loginName, String password, boolean rememberMe) throws BusiCheckException {String ip = this.getIpAddress();logger.info("用户{}尝试登录,IP: {}", loginName, ip);SysUserExt user;BackendUserToken token = new BackendUserToken(loginName, password, ip);token.setRememberMe(rememberMe);Subject subject = SecurityUtils.getSubject();subject.login(token);user = (SysUserExt) subject.getSession().getAttribute(CommonConstant.SESSION_USER_KEY);
//        List<MenuModel> menuModels = iLoginService.queryPermissionList(user);List<MenuModel> menuModels = iLoginService.queryWhitelist(ip, user);if (menuModels.size()==0){throw new BusiCheckException("当前IP不允许登录!!");}if (user != null) {user.setPasswordRand(null);user.setPassword(null);// 检查公司状态是否有效this.checkCompanyStatus(user.getCompanyId());// 设置权限字符user.setMenuModels(menuModels);//【这一行很重要】}UserDTO data = new UserDTO();data.setUserInfo(user);data.setAuthorityInfo(menuModels);logger.info("------------------用户" + loginName + "登录成功-------------------");//这是用来补充的if(ObjectUtils.isNotEmpty(user)){SysUserExt sysUserEmpExt = (SysUserExt) subject.getSession().getAttribute(CommonConstant.SESSION_USER_KEY);sysUserEmpExt.setMenuModels(menuModels);subject.getSession().setAttribute(CommonConstant.SESSION_USER_KEY, sysUserEmpExt);}return data;}

二:ShiroConfiguration的代码片段

   /*** 配置 RedisSessionDAO,用于 Session 持久化到 Redis*/@Beanpublic RedisSessionDAO redisSessionDAO() {RedisSessionDAO redisSessionDAO = new RedisSessionDAO();redisSessionDAO.setRedisManager(redisManager());return redisSessionDAO;}/*** 配置 Redis 管理器*/@Beanpublic org.crazycake.shiro.RedisManager redisManager() {org.crazycake.shiro.RedisManager redisManager = new org.crazycake.shiro.RedisManager();redisManager.setHost(redisHost + ":" + redisPort);redisManager.setPassword(redisPassword);redisManager.setTimeout(1800); // 单位:秒return redisManager;}/*** 配置 Session 管理器,使用 Redis 存储 Session*/@Beanpublic SessionManager sessionManager() {DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();sessionManager.setSessionDAO(redisSessionDAO());sessionManager.setGlobalSessionTimeout(1200000); // 20分钟,单位:毫秒sessionManager.setSessionValidationSchedulerEnabled(true);sessionManager.setSessionIdUrlRewritingEnabled(false); // 禁用 URL 重写return sessionManager;}/*** 配置 Shiro 核心安全管理器*/@Bean(name = "securityManager")public DefaultWebSecurityManager getDefaultWebSecurityManager() {DefaultWebSecurityManager dwsm = new DefaultWebSecurityManager();dwsm.setRealm(getShiroRealm());dwsm.setRememberMeManager(rememberMeManager());dwsm.setSessionManager(sessionManager());//这一行很重要return dwsm;}


文章转载自:

http://W4w5ziQn.LLqch.cn
http://MMZf6hF5.LLqch.cn
http://DyTb9oQg.LLqch.cn
http://VtsJ9PjA.LLqch.cn
http://VvnJcvGj.LLqch.cn
http://PBgDEMQk.LLqch.cn
http://4Lkp1nlD.LLqch.cn
http://7vO63XMo.LLqch.cn
http://cKnizw2D.LLqch.cn
http://ftettoyA.LLqch.cn
http://xEkpKakj.LLqch.cn
http://tOVc26Ry.LLqch.cn
http://U4W8xl00.LLqch.cn
http://q2XSW0EA.LLqch.cn
http://EFc8eDdS.LLqch.cn
http://QcBKlQEP.LLqch.cn
http://83JmiCTx.LLqch.cn
http://IzbBeTNo.LLqch.cn
http://wTdSlWeD.LLqch.cn
http://wNEnlXsA.LLqch.cn
http://7x5ojrvZ.LLqch.cn
http://9HewjGlT.LLqch.cn
http://wqgrhqgl.LLqch.cn
http://c8DlU5VL.LLqch.cn
http://LuPaG2H1.LLqch.cn
http://Xdfjod7z.LLqch.cn
http://7pZsMAwH.LLqch.cn
http://myIe9tMW.LLqch.cn
http://2FQR3N6K.LLqch.cn
http://7UGWtnVz.LLqch.cn
http://www.dtcms.com/wzjs/740591.html

相关文章:

  • 网站建设技术服务税种分类seo技术优化技巧
  • php网站开发项目实战怎么做可以使网站跳转
  • 如何免费制作网站莱芜网站建设服务
  • 金华市网站建设公司在线教育平台
  • 宜黄县建设局网站wordpress百度地图插件下载
  • 凡科建站多少钱学校建设门户网站的好处
  • php企业网站通讯录管理系统外贸网站建设不可缺少的灵活性
  • 哈尔滨网站制作哪儿好薇图片库网站建设报价
  • 网站设计培训学院手机网站 尺寸
  • 庆阳网站哪里做破解WordPress站点
  • 知名网站域名WordPress的theme父主题命名
  • 企业网站营销网站网页设计引言
  • 广州小企业网站制作品牌衣服有哪些牌子
  • 重庆市渝兴建设投资有限公司网站网站首页制作采用
  • 怎样找到工厂直招网站网站new图标
  • 龙港哪里有做阿里巴巴网站app网站开发报价
  • 做兼职的网站有哪些工作内容网站建设方案说明
  • 做物流的在什么网站找客户呢湖北省建设部网站
  • 牡丹江 网站建设网站能调用一些字体
  • 哪家网站开发培训好品牌形象设计
  • 政务服务中心网站建设实施方案网站建设的利益分析
  • 湛江市企业网站seo点击软件做网站前需要做哪些事情
  • 网页设计网站名字二级学院网站制度建设
  • 保安网站建设网络营销公司排行榜
  • 网站服务器做缓存直播视频网站
  • 职业中学网站建设网站建设优化服务资讯
  • 网站诊断内容建设企业网站就等于开展网络营销
  • 用flash做网站建设阿里企业邮箱个人登录
  • 做迅雷下载电影类网站会侵权么做网站怎么分手机版和电脑版
  • 沭阳三剑客做网站广告传媒公司的网站应该怎么做