这篇博客就来写一写之前学习shiro框架整合的时候,产生的一些问题,相信大家在学习的时候也有相应的一些疑惑。接下来就针对shiro中的session和cookie来捋一捋。
shiro整合学习的总结
-
shiro+redis集成,避免每次访问有权限的链接都会去执行MyShiroRealm.doGetAuthenticationInfo()方法来查询当前用户的权限,因为实际情况中权限是不会经常变得,这样就可以使用redis进行权限的缓存。
-
实现shiro链接权限的动态加载,之前要添加一个链接的权限,要在shiro的配置文件中添加filterChainDefinitionMap.put(“/add”, “roles[100002],perms[权限添加]”),这样很不方便管理,一种方法是将链接的权限使用数据库进行加载,另一种是通过init配置文件的方式读取。
-
Shiro 自定义权限校验Filter定义,及功能实现。
-
Shiro Ajax请求权限不满足,拦截后解决方案。这里有一个前提,我们知道Ajax不能做页面redirect和forward跳转,所以Ajax请求假如没登录,那么这个请求给用户的感觉就是没有任何反应,而用户又不知道用户已经退出了。
-
控制同一个用户的在线数量。(挤出之前的登录用户)
-
Shiro 登录后跳转到最后一个访问的页面
-
在线显示,在线用户管理(踢出登录)。
-
登录注册密码加密传输。
-
集成动态验证码。
-
记住我的功能。关闭浏览器后还是登录状态。
·······················································································································································
此项目下载地址: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已经不存在了。
cookie
当浏览一个网站的时候,网站返回给你一个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 。在登录时,代码也很简单:
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我又下面几点疑惑,忘大神指点:
-
我在测试的时候,使用了remenberme的功能后,我将登录生成的cookie复制出来,我不管重新登录相同用户多少次,我带上这个cookie访问的时候,还是不会走身份验证这个拦截器。只走权限验证的拦截器,也就是说用户在使用退出登录后。之前的cookie还是有效的。并没有清除。怎么清除cookie。不是所清除客户端的cookie,而是清除服务器记住的cookie序列化文件。
-
有没有什么好的方法可以防止盗取cookie,进行xss攻击。
网上找了一个思路:
- 用户选择了 “记住我” 成功登录后,将会把 username、随机产生的序列号、生成的 token 存入一个数据库表中,同时将它们的组合生成一个 cookie 发送给客户端浏览器。
- 当下一次没有登录的用户访问系统时,首先检查 cookie,如果对应 cookie 中包含的 username、序列号和 token 与数据库中保存的一致,则表示其通过验证,系统将重新生成一个新的 token 替换数据库中对应组合的旧 token,序列号保持不变,同时删除旧的 cookie,重新生成包含新生成的 token,就的序列号和 username 的 cookie 发送给客户端。
- 如果检查 cookie 时,cookie 中包含的 username 和序列号跟数据库中保存的匹配,但是 token 不匹配。这种情况极有可能是因为你的 cookie 被人盗用了,由于盗用者使用你原本通过认证的 cookie 进行登录了导致旧的 token 失效,而产生了新的 token。这个时候 shiro就可以发现 cookie 被盗用的情况,它将删除数据库中与当前用户相关的所有 token 记录,这样盗用者使用原有的 cookie 将不能再登录,同时提醒用户其帐号有被盗用的可能性。
- 如果对应 cookie 不存在,或者包含的 username 和序列号与数据库中保存的不一致,那么将会引导用户到登录页面。
这样处理有一个不好的地方就是:必须要每次用户要再次操作的时候才会发现cookie被盗用,如果被盗用的cookie是用户最后一次操作生成的cookie呐。
我到觉得控制用户登录人数为只能一个人登录一个帐号,还比上面这个方便些,不会反复的生成cookie,写入cookie。但是也不好,没有解决服务器上的cookie没有根据用户的退出而失效的这个问题。
网友评论
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="MyRealm" />
<!-- 记住我 -->
<property name="rememberMeManager" ref="rememberMeManager"/>
</bean>