上一篇文章,在解决了两个用户登录的问题之后,又发现了新的问题:
在同一个浏览器先登录用户A,再去访问原本用户B需要登录才可以访问的链接,就会直接进入,不再跳转回登录页面
当直接访问用户B的链接时,获取已经登录的用户对象,取出来的仍然是用户A
首先,找到第一个问题的原因,观察配置文件的时候,发现用户A和用户B使用的认证规则都是shiro中的FormAuthenticationFilter类,而FormAuthenticationFilter类继承自AuthenticatingFilter类,在该类中,isAccessAllowed函数,用来检测用户是否登录;进到isAccessAllowed函数中:
发现父类的isAccessAllowed函数,是控制的关键,再次进入到isAccessAllowed函数中:
检测是否允许访问的,只是检测subject对象是否为认证状态(也就是对象中是否存在登录信息)
所以在同一浏览器中,用户A已经登录,访问用户B的链接时,Subject对象中已经存在信息,所以会允许访问,而同时,第二个问题也找到了
这个问题,在不同的浏览器访问,就不会出现,所以感觉是sessionid的问题,但是为每个身份配置了不同的sessionid也没起作用(可能是我处理的方法不太对😔)。于是想到了另外一种解决办法
—————————我是华丽的分割线—————————
我们在自定义的realm对象中,最后一步构造了AuthenticationInfo对象
可以看出,是吧自定义对象,和当前realm的名称传入到SimpleAuthenticationInfo类中,点进去看SimpleAuthenticationInfo的构造函数:
!
上面的是我们原来使用的,发现是把我们传递的对象放在了SimplePrincipalCollection类中,看名字,这个类应该是可以储存多个对象。继续往下走,发现SimplePrincipalCollection类中,定义了add和addAll两个函数,而且其中一个构造函数的参数还是Collection类型,证明是可以储存多个值的,所以应该是在创建SimpleAuthenticationInfo类的时候,也应该可以传入PrincipalCollection才对,果然在我们之前的构造函数下方又发现了一个构造函数
这回大概有了解决的思路了:
1.在realm处理登录的时候,先查询原来是不是已经存在SimplePrincipalCollection对象
2.如果不存在,则证明当前用户是第一个用户,直接进行正常的登录逻辑
3.如果存在,则证明已经登录其他的用户,获取SimplePrincipalCollection对象,并调用add函数将当前对象信息加入,在创建SimpleAuthenticationInfo对象。
对应的关键位置的代码如下:
登录部分处理完,之后还要对isAccessAllowed函数进行重写,根据访问的url,手动检测对应的对象信息是否存在
这些工作做完之后,记得修改xml配置文件中引用类的路径,把原来的org.apache.shiro.web.filter.authc.FormAuthenticationFilter换为我们重写的类路径。
同时,在登陆成功后,获取用户信息的时候,也要改为subject的getPrincipals()函数,获取PrincipalCollection类,再在其中获取到当前url需要的内容
虽然没有找到其他人的解决方案,但是好歹还是自己通过看源码+Debug的方式,找到了需要重写的函数和对象,解决了这个问题