shiro中 UnknownAccountException
一 shiro的session、request和response与服务端容器自身的这三个对象的关系
在web.xml中配置了一个Filter,拦截/*,所有的uri。在拦截器中还会调用ShiroFilter这个filter,如下图1,可以看出ShiroFilter继承AbstractShiroFilter,查看AbstractShiroFilter源码的doFilterInternal方法,(可以看上一篇shiro中关于这个方法的作用)。在这个方法中如图2, protected ServletRequest prepareServletRequest(ServletRequest request, ServletResponse response, FilterChain chain) ,protected ServletResponse wrapServletResponse(HttpServletResponse orig, ShiroHttpServletRequest request) 会调用这两个方法。如图3所示,到这里可以看出AbstractShiroFilter会将容器的这三个内置对象包装成shiro的对应对象,这里实际是用到了装饰者模式。所以在web环境shiro本身并没有新建自己的域对象,而是将原生的对象包装了一下。
图1:
图2:
图3:
二 在项目中踩过的一个坑
需求是这样的:当用户的关联的某个内容在后台cms系统中审核通过后,此后这个用户在第一次登录后要提醒这个用户。开发人员写了一个接口afterLogin,获取是否已经提醒过。前端人员就在项目的header.jsp中直接调用了这个接口,head.jsp是全局共享的页面头,由于afterLogin 是要在登录后才可以访问的。所以在未登录的情况下访问这个接口会重定向调用login接口,如下图4;由于是ajax请求,这将导致浏览器地址不会改变。所以界面没反应。但是login接口的头信息中Set-Cookie sid=deleteMe,这表示在后端清除了session并通知浏览器清除这个cookie,这将导致再次请求服务端时候将不带sid信息,如图6,请求request headers中没有带上sid,后端会新建一个session了。 坑:在找回密码页面,由于引用了header.jsp并且未登录,这个页面要输入图片验证码,由于请求了afterLogin接口,后端与验证码绑定的session被清除了,在输入验证码校验时如图6,没有带上sid,并且此时这个session已经不存在了,所以在Jcapthca中会抛出空指针,是因为新建的session中没有验证码,报错如图7。有的地方请求后后端会报错UnknownAccountException session异常,这个也是由于afterLogin引起的,因为这些请求带上了sid,但是这个sid对应的session已经不存在了,所以报错UnknownAccountException 。总的来说浏览器请求login页面地址,服务端会清除已经存在的session,这是因为要在登录后建立一个新的session。若请求仍然带上上一个已经不存在的session的sid 的话,就会出现UnknownAccountException 异常了。
图4:
图5:
图6:
图7:
三 JESSIONID和sid关系
由于ShiroFilter将容器的request等都包装成shiro的对应对象了,所以在后端代码中获取到的都是shiro中的对象,所以JSESSIONID实际上并没有用到,request.getSession都是通过sid标识来获取的。