redis-shiro session共享,登陆后subject中principal 为空

看过我的上一篇文章 redis-shiro session共享,序列化大坑的人,你可能遇到一个新的问题,就是登陆后再去请求的时候,报错This subject is anonymous
具体的错误信息如下:
This subject is anonymous - it does not have any identifying principals and authorization operations require an identity to check against. A Subject instance will acquire these identifying principals automatically after a successful login is performed be executing org.apache.shiro.subject.Subject.login(AuthenticationToken) or when ‘Remember Me’ functionality is enabled by the SecurityManager. This exception can also occur when a previously logged-in Subject has logged out which makes it anonymous again. Because an identity is currently not known due to any of these conditions, authorization is denied.
这是再验证用户的时候就报错了,都没有走到权限验证.
我就不啰嗦http session工作原理了,直接上干货.
Subject中principal为空,为什么?
查源码看他什么时候创建的
DefaultSecurityManager中的createSubject

public Subject createSubject(SubjectContext subjectContext) {//create a copy so we don't modify the argument's backing map:SubjectContext context = copy(subjectContext);//ensure that the context has a SecurityManager instance, and if not, add one:context = ensureSecurityManager(context);//Resolve an associated Session (usually based on a referenced session ID), and place it in the context before//sending to the SubjectFactory.  The SubjectFactory should not need to know how to acquire sessions as the//process is often environment specific - better to shield the SF from these details:context = resolveSession(context);//Similarly, the SubjectFactory should not require any concept of RememberMe - translate that here first//if possible before handing off to the SubjectFactory:context = resolvePrincipals(context);Subject subject = doCreateSubject(context);//save this subject for future reference if necessary://(this is needed here in case rememberMe principals were resolved and they need to be stored in the//session, so we don't constantly rehydrate the rememberMe PrincipalCollection on every operation).//Added in 1.2:save(subject);return subject;}

context = resolvePrincipals(context);该方法是为subjectContext找principal的

@SuppressWarnings({"unchecked"})protected SubjectContext resolvePrincipals(SubjectContext context) {PrincipalCollection principals = context.resolvePrincipals();if (isEmpty(principals)) {log.trace("No identity (PrincipalCollection) found in the context.  Looking for a remembered identity.");principals = getRememberedIdentity(context);if (!isEmpty(principals)) {log.debug("Found remembered PrincipalCollection.  Adding to the context to be used " +"for subject construction by the SubjectFactory.");context.setPrincipals(principals);// The following call was removed (commented out) in Shiro 1.2 because it uses the session as an// implementation strategy.  Session use for Shiro's own needs should be controlled in a single place// to be more manageable for end-users: there are a number of stateless (e.g. REST) applications that// use Shiro that need to ensure that sessions are only used when desirable.  If Shiro's internal// implementations used Subject sessions (setting attributes) whenever we wanted, it would be much// harder for end-users to control when/where that occurs.//// Because of this, the SubjectDAO was created as the single point of control, and session state logic// has been moved to the DefaultSubjectDAO implementation.// Removed in Shiro 1.2.  SHIRO-157 is still satisfied by the new DefaultSubjectDAO implementation// introduced in 1.2// Satisfies SHIRO-157:// bindPrincipalsToSession(principals, context);} else {log.trace("No remembered identity found.  Returning original context.");}}return context;}

他先找当前context中有没有,如果没有去找RememberMeManager中找,再看注释,以前还有上session中找,只不过因为某些原因移除了,由此我们可以找出2种解决方案.

  1. 启用RememberMeManager,这一点我在搜索的时候没有见到人提过,只是看别人的shiro配置代码中有一句securityManager.setRememberMeManger(new CookieRememberMeManger());如下图

    这是没有任何意义的,因为即使你不写这句,
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();securityManager的构造函数中也有这一句.
    正确的做法应该是在登录的时候启用rememberMe,如下:
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(userName, password);usernamePasswordToken.setRememberMe(true);
  1. 第二种解决方案就是如注释所说,在Session种去查找pricipal,这需要你把Pricipal信息存到Session中,解决方案就是继承DefaultWebSecurityManager ,重写resolvePrincipals方法:
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SubjectContext;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.data.redis.core.RedisTemplate;public class MyWebSecurityManager extends DefaultWebSecurityManager {@Overrideprotected SubjectContext resolvePrincipals(SubjectContext context) {PrincipalCollection principals = context.resolvePrincipals();if (principals == null || principals.isEmpty()) {principals = getRememberedIdentity(context);if (principals == null || principals.isEmpty()) {context.setPrincipals(principals);}}if (principals == null || principals.isEmpty()) {//TODO:从你存储的session中读取principal,如果你把session存在redis中,就从redis中读取它}return context;}
}

看起来是不是很简单,当我第一次遇到它的时候,搜索错误信息,有人说是过滤器链的问题,有人说是这个异常加个异常处理,完全找不到真正的原因.
苦逼的爬了2天源代码,把shiro的原理搞明白才解决了问题.
希望能帮到看到这里的你.

redis-shiro session 共享subject中principal 为空相关推荐

  1. 分布式中使用 Redis 实现 Session 共享(中)

    http://blog.jobbole.com/91874/ 原文出处: 焰尾迭   欢迎分享原创到伯乐头条 上一篇介绍了一些redis的安装及使用步骤,本篇开始将介绍redis的实际应用场景,先从最 ...

  2. 使用Shiro+Redis实现Session共享

    章节目录 1. 为什么要实现Session共享? 1.1 负载均衡 1.2 负载均衡中的Session问题 1.3 案例演示 2. Shiro架构 3. Shiro集成Redis 1. 为什么要实现S ...

  3. Tomcat通过Redis实现session共享的完整部署记录

    对于生产环境有了一定规模的tomcat集群业务来说,要实现session会话共享,比较稳妥的方式就是使用数据库持久化session.为什么要持久化session(共享session)呢?因为在客户端每 ...

  4. Rainbond最佳实践:Tomcat配置Redis实现Session共享

    Rainbond:生产级无服务器PaaS Rainbond是国内首个开源的生产级无服务器PaaS,深度整合基于Kubernetes的容器管理.多类型CI/CD应用构建与交付.多数据中心的资源管理等技术 ...

  5. redis实现session共享,哨兵

    一.Redis介绍 1.redis是key-value的存储系统,属于非关系型数据库 2.特点:支持数据持久化,可以让数据在内存中保存到磁盘里(memcached:数据存在内存里,如果服务重启,数据会 ...

  6. 单点登录实现(spring session+redis完成session共享)

    一.前言 项目中用到的SSO,使用开源框架cas做的.简单的了解了一下cas,并学习了一下 单点登录的原理,有兴趣的同学也可以学习一下,写个demo玩一玩. 二.工程结构 我模拟了 sso的客户端和s ...

  7. php 获取cookieid,Redis实现Session共享详解

    Redis实现Session共享 这几天在做session共享这么一个小模块,也查了好多资料,给我的感觉,就是太乱了,一直找不到我想要的东西,几乎全部实现方法都与我的想法不一样,在这里,我总结一下自己 ...

  8. C#session共享+redis_技术干货分享:基于SpringBoot+Redis的Session共享与单点登录

    categories: 架构 author: mrzhou tags: SpringBoot redis session 单点登录 基于SpringBoot+Redis的Session共享与单点登录 ...

  9. 项目分布式部署那些事(1):ONS消息队列、基于Redis的Session共享,开源共享

    因业务发展需要现在的系统不足以支撑现在的用户量,于是我们在一周之前着手项目的性能优化与分布式部署的相关动作. 概况 现在的系统是基于RabbitHub(一套开源的开发时框架)和Rabbit.WeiXi ...

最新文章

  1. 心急的C小加《贪心》
  2. php 静态方法和非静态方法的调用说明
  3. mysql 自后向前截取函数_【转载】Sqlserver使用Right函数从最右边向前截取固定长度字符串...
  4. 【BZOJ3630】[JLOI2014]镜面通道 几何+最小割
  5. dasblog的安装
  6. 基于Sbo SDK的Add-on插件开发实例
  7. 网站打开速度多少毫秒为正常_个人做shopify-怎么测试和优化网站打开速度
  8. python中的括号不是西文吗_二级Python---python语言的基本语法元素(Day1)
  9. 理解 Java 核心基础精髓
  10. Java 设计模式六大原则
  11. ds6708 symbol 驱动_Symbol DS6708扫描器
  12. Python爬虫——全网获取音乐
  13. 【你好,windows】Windows 7 X64旗舰纯净版版(NVME和USB3.0集合总裁万能网
  14. pla3d打印材料密度_FDM 3D打印机的常用耗材PLA的密度 创想三维
  15. 一元非线性方程求根的算法——二分法/牛顿迭代法
  16. 分析与提取QQ木马盗号技术
  17. UML系列——包图Package
  18. WiFi 运动,心跳,跌倒监测 (一)
  19. 【IPD】IPDPLM
  20. 数据库实验2——使用SQL语句创建、修改和删除基本表

热门文章

  1. 基于JSP的网上在线租车系统平台设计与实现
  2. 记一次mysql5.7的新特性derived_merge的坑
  3. 在html页面引入外部html的方法 (使用第三方插件)
  4. 浅谈一下个人基于IRIS后端业务开发框架的理解
  5. ROS安装/// rosdep update/the read operation is timed out
  6. 信息级联(Information cascade)
  7. 关于mysql数据库三范式
  8. 斐波那契数列的四种实现方式(C语言)
  9. ja-netfilter-all,IntelliJ IDEA 2021.3.2 (Ultimate Edition)
  10. 知识图谱本体建模之RDF、RDFS、OWL详解