这篇博客就来写一写之前学习shiro框架整合的时候,产生的一些问题,相信大家在学习的时候也有相应的一些疑惑。接下来就针对shiro中的session和cookie来捋一捋。

shiro整合学习的总结


  1. shiro+redis集成,避免每次访问有权限的链接都会去执行MyShiroRealm.doGetAuthenticationInfo()方法来查询当前用户的权限,因为实际情况中权限是不会经常变得,这样就可以使用redis进行权限的缓存。

  2. 实现shiro链接权限的动态加载,之前要添加一个链接的权限,要在shiro的配置文件中添加filterChainDefinitionMap.put(“/add”, “roles[100002],perms[权限添加]”),这样很不方便管理,一种方法是将链接的权限使用数据库进行加载,另一种是通过init配置文件的方式读取。

  3. Shiro 自定义权限校验Filter定义,及功能实现。

  4. Shiro Ajax请求权限不满足,拦截后解决方案。这里有一个前提,我们知道Ajax不能做页面redirect和forward跳转,所以Ajax请求假如没登录,那么这个请求给用户的感觉就是没有任何反应,而用户又不知道用户已经退出了。

  5. 控制同一个用户的在线数量。(挤出之前的登录用户)

  6. Shiro 登录后跳转到最后一个访问的页面

  7. 在线显示,在线用户管理(踢出登录)。

  8. 登录注册密码加密传输。

  9. 集成动态验证码。

  10. 记住我的功能。关闭浏览器后还是登录状态。

·······················································································································································

个人博客:http://z77z.oschina.io/

此项目下载地址:https://git.oschina.net/z77z/springboot_mybatisplus

·······················································································································································

session


session是大家比较熟悉的功能,因为HTTP协议是无状态的,网站为了在多个请求之间传递数据就使用了session这个东西,session是存储在网站服务器上的某个地方,比如内存、数据库或者其他的什么东西,在我的配置中是用redis存储的,因为我使用了Shiro的Native Session Manager,替代了Tomcat本身的Session Manager,并且为Shiro的Native Session Manager配置了redis的SessionDAO,当然这个我是直接使用的一个开源插件,里面已经帮我们很好的实现了cacheManager,sessionManager,redisSessionDAO这些。直接使用就可以了。

shiro_redis插件地址:http://www.oschina.net/p/shiro-redis

所以所有的session会话都是缓存在redis里面的。对session的增删改查都是在操作redis数据库来完成。所以如果将redis进行集群的话,session会话也就会达到集群的目的。后面我专门写博客来分享。

在这种情况下服务器的Session就存储在redis里面,如果某个Session过期(比如关闭了浏览器或者超时),此条Session就会从redis里面永久删除,下次的请求将不能使用Session里面的数据。所以说即使有些url设置的是”user”级别的(也就是说不用登录即可访问,只须设置了rememberMe),但是如果这些url使用了Session里面的数据,就会抛出异常,因为此时这个用户对应的Session已经不存在了。


当浏览一个网站的时候,网站返回给你一个Session Cookie和一个RememberMe Cookie,Session Cookie很好理解,就是为了此次的对话,一旦关闭了浏览器或者超时了Session Cookie就没用了。但是RememberMe Cookie不太一样,Shiro默认的RememberMe Cookie的时长是一年,所以不用担心这个Cookie的情况。RememberMe Cookie实际就是Shiro把这个用户的信息加密一下放到cookie里面,下次就可以根据这个cookie来进行判断这是哪个用户。

主要讲下shiro的rememberMe cookie。在shiro中有一个类实现了rememberMe功能, org.apache.shiro.web.mgt.CookieRememberMeManager 。在登录时,代码也很简单:

1
2
3
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
token.setRememberMe(true);
subject.login(token);

RememberMe这个参数设置为true后,在登陆的时候就会在客户端设置remenberme的相应cookie。下次访问带上这个cookie,访问链接为user链接器的,就不需要进行登录验证,直接进入权限验证。下面是完整的处理过程:

  • 得到principals对象
  • 通过配置的key,使用aes加密
  • 将加密后的值再通过base64解密
  • 当客户端带着这个rememberMe cookie访问时,将会按照下面的过程来寻找已记住的身份信息:
  • 获取rememberMe cookie的值
  • Base64解码
  • 使用AES解密
  • 使用ObjectInputStream进行反序列化

这样不需要进入身份验证的拦截器,就直接从cookie中获取到了登录信息。

未解决疑惑


session整个流程很好理解,我们使用的插件,对session的操作理解可以去看我之前写的在线用户管理和控制在线人数功能,基本都是对session的操作。

https://my.oschina.net/z707z/blog/852189

对于cookie我又下面几点疑惑,忘大神指点:

  1. 我在测试的时候,使用了remenberme的功能后,我将登录生成的cookie复制出来,我不管重新登录相同用户多少次,我带上这个cookie访问的时候,还是不会走身份验证这个拦截器。只走权限验证的拦截器,也就是说用户在使用退出登录后。之前的cookie还是有效的。并没有清除。怎么清除cookie。不是所清除客户端的cookie,而是清除服务器记住的cookie序列化文件。

  2. 有没有什么好的方法可以防止盗取cookie,进行xss攻击。

网上找了一个思路:

  1. 用户选择了 “记住我” 成功登录后,将会把 username、随机产生的序列号、生成的 token 存入一个数据库表中,同时将它们的组合生成一个 cookie 发送给客户端浏览器。
  2. 当下一次没有登录的用户访问系统时,首先检查 cookie,如果对应 cookie 中包含的 username、序列号和 token 与数据库中保存的一致,则表示其通过验证,系统将重新生成一个新的 token 替换数据库中对应组合的旧 token,序列号保持不变,同时删除旧的 cookie,重新生成包含新生成的 token,就的序列号和 username 的 cookie 发送给客户端。
  3. 如果检查 cookie 时,cookie 中包含的 username 和序列号跟数据库中保存的匹配,但是 token 不匹配。这种情况极有可能是因为你的 cookie 被人盗用了,由于盗用者使用你原本通过认证的 cookie 进行登录了导致旧的 token 失效,而产生了新的 token。这个时候 shiro就可以发现 cookie 被盗用的情况,它将删除数据库中与当前用户相关的所有 token 记录,这样盗用者使用原有的 cookie 将不能再登录,同时提醒用户其帐号有被盗用的可能性。
  4. 如果对应 cookie 不存在,或者包含的 username 和序列号与数据库中保存的不一致,那么将会引导用户到登录页面。

这样处理有一个不好的地方就是:必须要每次用户要再次操作的时候才会发现cookie被盗用,如果被盗用的cookie是用户最后一次操作生成的cookie呐。

我到觉得控制用户登录人数为只能一个人登录一个帐号,还比上面这个方便些,不会反复的生成cookie,写入cookie。但是也不好,没有解决服务器上的cookie没有根据用户的退出而失效的这个问题。