Java识堂▲还有这么多解决方案,用户登陆除了cookie和session( 二 )


如果不考虑以上三个问题 , 这种管理方式比较值得使用 , 尤其是一些小型的web应用 。 但是一旦应用将来有扩展的必要 , 那就得谨慎对待前面的三个问题 。 如果真要在项目中使用这种方式 , 推荐结合单点登录框架如CAS一起用 , 这样会使应用的扩展性更强 。
2.cookie-based的管理方式由于前一种方式会增加服务器的负担和架构的复杂性 , 所以后来就有人想出直接把用户的登录凭证直接存到客户端的方案 , 当用户登录成功之后 , 把登录凭证写到cookie里面 , 并给cookie设置有效期 , 后续请求直接验证存有登录凭证的cookie是否存在以及凭证是否有效 , 即可判断用户的登录状态 。 使用它来实现会话管理的整体流程如下:
1)用户发起登录请求 , 服务端根据传入的用户密码之类的身份信息 , 验证用户是否满足登录条件 , 如果满足 , 就根据用户信息创建一个登录凭证 , 这个登录凭证简单来说就是一个对象 , 最简单的形式可以只包含用户id , 凭证创建时间和过期时间三个值 。
2)服务端把上一步创建好的登录凭证 , 先对它做数字签名 , 然后再用对称加密算法做加密处理 , 将签名、加密后的字串 , 写入cookie 。 cookie的名字必须固定(如ticket) , 因为后面再获取的时候 , 还得根据这个名字来获取cookie值 。 这一步添加数字签名的目的是防止登录凭证里的信息被篡改 , 因为一旦信息被篡改 , 那么下一步做签名验证的时候肯定会失败 。 做加密的目的 , 是防止cookie被别人截取的时候 , 无法轻易读到其中的用户信息 。
3)用户登录后发起后续请求 , 服务端根据上一步存登录凭证的cookie名字 , 获取到相关的cookie值 。 然后先做解密处理 , 再做数字签名的认证 , 如果这两步都失败 , 说明这个登录凭证非法;如果这两步成功 , 接着就可以拿到原始存入的登录凭证了 。 然后用这个凭证的过期时间和当前时间做对比 , 判断凭证是否过期 , 如果过期 , 就需要用户再重新登录;如果未过期 , 则允许请求继续 。
Java识堂▲还有这么多解决方案,用户登陆除了cookie和session
文章图片
这种方式最大的优点就是实现了服务端的无状态化 , 彻底移除了服务端对会话的管理的逻辑 , 服务端只需要负责创建和验证登录cookie即可 , 无需保持用户的状态信息 。 对于第一种方式的第二个问题 , 用户会话信息共享的问题 , 它也能很好解决:因为如果只是同一个应用做集群部署 , 由于验证登录凭证的代码都是一样的 , 所以不管是哪个服务器处理用户请求 , 总能拿到cookie中的登录凭证来进行验证;如果是不同的应用 , 只要每个应用都包含相同的登录逻辑 , 那么他们也是能轻易实现会话共享的 , 不过这种情况下 , 登录逻辑里面数字签名以及加密解密要用到的密钥文件或者密钥串 , 需要在不同的应用里面共享 , 总而言之 , 就是需要算法完全保持一致 。
这种方式由于把登录凭证直接存放客户端 , 并且需要cookie传来传去 , 所以它的缺点也比较明显:
1)cookie有大小限制 , 存储不了太多数据 , 所以要是登录凭证存的消息过多 , 导致加密签名后的串太长 , 就会引发别的问题 , 比如其它业务场景需要cookie的时候 , 就有可能没那么多空间可用了;所以用的时候得谨慎 , 得观察实际的登录cookie的大小;比如太长 , 就要考虑是非是数字签名的算法太严格 , 导致签名后的串太长 , 那就适当调整签名逻辑;比如如果一开始用4096位的RSA算法做数字签名 , 可以考虑换成1024、2048位;
2)每次传送cookie , 增加了请求的数量 , 对访问性能也有影响;
3)也有跨域问题 , 毕竟还是要用cookie 。
相比起第一种方式 , cookie-based方案明显还是要好一些 , 目前好多web开发平台或框架都默认使用这种方式来做会话管理 , 比如php里面yii框架 , 这是我们团队后端目前用的 , 它用的就是这个方案 , 以上提到的那些登录逻辑 , 框架也都已经封装好了 , 实际用起来也很简单;asp.net里面forms身份认证 , 也是这个思路 , 这里有一篇好文章把它的实现细节都说的很清楚: