HTTP 是无状态的协议(对于事务处理没有记忆能力,每次客户端和服务端会话完成时,服务端不会保存任何会话信息):每个请求都是完全独立的,服务端无法确认当前访问者的身份信息,无法分辨上一次的请求发送者和这一次的发送者是不是同一个人。
所以服务器与浏览器为了进行会话跟踪(知道是谁在访问我),就必须主动的去维护一个状态,这个状态用于告知服务端前后两个请求是否来自同一浏览器。
cookie认证登录超时一般都是在服务端设置cookie有效时间。
cookie认证特点最大的就是用户信息保存在浏览器。
第一点是cookie的严重问题。
虽然session仍然有缺陷,但是现在大部分的Web应用还在使用session认证。后来出现了token认证。
token又叫令牌,本质上就是一串无意义的字符串,一般放在请求头里,请求头key一般是"Authorization",当然也可以和服务端约定好自定义成其他的,只要服务端能够从请求头中拿到token就好了。token认证的出现最大的特点就是让登陆认证不再依赖于cookie机制了,将token放在了请求头里,那些由于cookie机制导致的弊端自然就没有了。
如果token携带了用户信息,不就不需要每次请求都访问数据库查了嘛,从token中直接解析出用户信息以及用户登录状态进行校验,这就是后来的JWT。给浏览器返回的token是一串带着用户信息的字符串
JWT全称是Java Web Token。其实就是特殊的token,理解起来就是携带着用户信息的token。所以JWT认证和token认证本质上是一样的。只不过token认证的用户信息是从数据库里查的。而JWT认证的用户信息是直接从token解析出来的。
基于 token 的用户认证是一种服务端无状态的认证方式,服务端不用存放 token 数据。用解析token 的计算时间换取 session 的存储空间,从而减轻服务器的压力,减少频繁的查询数据库。
基于session认证的单点登录还有局部会话和全局会话两个概念,即浏览器和应用服务器之间建立的是局部会话。和认证中心服务器之间建立的全局会话。
也就是用户登录成功之后、在认证中心服务器和应用服务器都保存用户信息和登录状态的session,浏览器中的表现就是应用服务和认证中心服务的域下面都会存着对应的sessionID的cookie;
需要注意的是,基于session认证的单点登录在集群环境中是不需要做session共享或者nginx配置ip_hash的。集群中各个节点就相当于各个子系统了,没有局部会话session那就重新走一遍自动单点认证,反正不需要用户手动再输一遍密码就好了。
java实现基于session认证的单点登录需要两个jar包,cas-client-core和cas-server-core,即cas客户端和服务端,cas客户端就是图中的服务器A和B,cas服务端就是认证中心。这里主要看一下cas-client-core这个jar包,从中捋出部分源码对应一下图中的流程。
在AuthenticationFilter的doFilter()方法中,服务端校验如果局部会话和ticket都没有,则将浏览器重定向到单点登录地址:
java实现基于session认证的单点登录需要两个jar包,cas-client-core和cas-server-core,即cas客户端和服务端,cas客户端就是图中的服务器A和B,cas服务端就是认证中心。这里主要看一下cas-client-core这个jar包,从中捋出部分源码对应一下图中的流程。
在AuthenticationFilter的doFilter()方法中,服务端校验如果局部会话和ticket都没有,则将浏览器重定向到单点登录地址:
其实单点登录的过程都差不多,就是认证方式的区别,理解了基于session认证的单点登录后,也很好理解基于JWT认证的单点登录。
安全性: Session 比 Cookie 安全,Session 是存储在服务器端的,Cookie 是存储在客户端的。
存取值的类型不同:Cookie 只支持存字符串数据,想要设置其他类型的数据,需要将其转换成字符串,Session 可以存任意数据类型
有效期不同: Cookie 可设置为长时间保持,比如我们经常使用的默认登录功能,Session 一般失效时间较短,客户端关闭(默认情况下)或者 Session 超时都会失效。
存储大小不同: 单个 Cookie 保存的数据不能超过 4K,Session 可存储数据远高于 Cookie,但是当访问量过多,会占用过多的服务器资源。
Session 是一种记录服务器和客户端会话状态的机制,使服务端有状态化,可以记录会话信息。 而Token 是令牌,访问资源接口(API)时所需要的资源凭证。Token 使服务端无状态化,不会存储会话信息。
Session 和 Token 并不矛盾,作为身份认证 Token 安全性比 Session 好,因为每一个请求都有签名还能防止监听以及重放攻击,而 Session 就必须依赖链路层来保障通讯安全了。如果你需要实现有状态的会话,仍然可以增加 Session 来在服务器端保存一些状态。
Token:服务端验证客户端发送过来的 Token 时,还需要查询数据库获取用户信息,然后验证Token 是否有效。
JWT:将 Token 和 Payload 加密后存储于客户端,服务端只需要使用密钥解密进行校验(校验也是 JWT 自己实现的)即可,不需要查询或者减少查询数据库,因为 JWT 自包含了用户信息和加密的数据。
任何一个服务器上的 session 发生改变(增删改),该节点会把这个 session 的所有内容序列化,然后广播给所有其它节点,不管其他服务器需不需要 session ,以此来保证 session同步
优点: 可容错,各个服务器间 session 能够实时响应。
缺点: 会对网络负荷造成一定压力,如果 session 量大的话可能会造成网络堵塞,拖慢服务器性能
采用 Ngnix 中的 ip_hash 机制,将某个 ip的所有请求都定向到同一台服务器上,即将用户与服务器绑定。 用户第一次请求时,负载均衡器将用户的请求转发到了 A 服务器上,如果负载均衡器设置了粘性 session 的话,那么用户以后的每次请求都会转发到 A 服务器上,相当于把用户和 A 服务器粘到了一块,这就是粘性 session 机制。
优点: 简单不需要对 session 做任何处理。
缺点: 缺乏容错性,如果当前访问的服务器发生故障,用户被转移到第二个服务器上时,他的 session信息都将失效。
适用场景: 发生故障对客户产生的影响较小;服务器发生故障是低概率事件。实现方式: 以 Nginx 为例,在 upstream 模块配置 ip_hash 属性即可实现粘性 session。
使用分布式缓存方案比如 Memcached 、Redis 来缓存 session,但是要求 Memcached 或 Redis必须是集群。
把 session 放到 Redis 中存储,虽然架构上变得复杂,并且需要多访问一次 Redis ,但是这种方案带来的好处也是很大的:
实现了 session 共享;
可以水平扩展(增加 Redis 服务器);
服务器重启 session 不丢失(不过也要注意 session 在 Redis 中的刷新/失效机制);
不仅可以跨服务器 session 共享,甚至可以跨平台(例如网页端和 APP 端)
将 session 存储到数据库中,保证 session 的持久化
优点: 服务器出现问题,session 不会丢失
缺点: 如果网站的访问量很大,把 session 存储到数据库中,会对数据库造成很大压力,还需要增加额外的开销维护数据库。