Java Web 之Token+Cookie+Session

发展史:

1. 早期的WEB基本上就是文档的浏览而已,服务器不需要记录谁在某个时间都浏览了什么文档,每次请求都是全新的HTTP协议。

2. 随着交互式WEB应用的兴起,例如在线购物网站,需要登录的网站等,则需要对会话进行管理,分别记录每个用户放入购物车中的商品,记录用户的登陆信息等,因为HTTP请求是无状态的,即:用户第一次发起请求与服务器建立连接并登录成功后,为了避免每次打开一个页面都需要登录一下,由此就出现了 cookie,Session。

3.使用Session的话,服务器要保存每个人的sessionId(客户端频繁的发出请求数据,服务端频繁的去数据库查询数据进行对比)当用户访问量增多的时占用空间,就越多耗费服务器性能。
—> 那么用多台服务器搭建集群来提高性能呢?当用户发送请求时无法在多台之间共享Session。
—> 那么再通过负载均衡将sessionId在多台之间互相复制呢?这样服务器性能也是个问题。
—> 那么使用Memcached把sessionId集中存储到一个地方,所有的机器都来访问这个地方的数据呢?如果负责sessionId的机器挂了,则所有人都得重新登陆了。
—> 那么再为这个负责sessionId的机器也做成集群,增加可靠性呢?。。。不管如何session还是个负担。

4.Session在大量访问时给服务器造成压力,在这种情况下,Token应用而生。 

一、Cookie:是服务器在本地机器上存储的小段文本并随每一个请求发送至同一个服务器,是一种在客户端保存用户信息的一种机制。

网络服务器用HTTP头向客户端发送cookies,在客户终端,浏览器解析这些cookies并将它们保存为一个本地文件,它会自动将同一服务器的任何请求缚上这些cookies 。

Cookie是由网络服务器通过HTTP头发送到客户端浏览器,浏览器把cookie以key-value的形式保存到某个目录下的文本文件中,下一次请求同一网站时会把该cookie发送给服务器。

浏览器为了确保cookie不被恶意使用,随意对cookie由一些限制:不会占用太多磁盘空间,只存储少量的数据(不同的浏览器有不同的存储大小,但一般不超过4KB,很多浏览器都限制一个站点最多保存20个cookie)。

Cookie 的组成:

名称(key)、值(value)、有效域(domain)、路径(域的路径,一般设置为全局:"\")、

失效时间:(若不设置则表示这个cookie的生命期为浏览器会话期间,关闭浏览器窗口,cookie就消失。这种生命期为浏览器会话期的cookie被称为会话cookie。会话cookie一般不存储在硬盘上而是保存在内存里,当然这种行为并不是规范规定的。若设置了过期时间,浏览器就会把cookie保存到硬盘上,关闭后再次打开浏览器,这些cookie仍然有效直到超过设定的过期时间。存储在硬盘上的cookie可以在不同的浏览器进程间共享,比如两个IE窗口。而对于保存在内存里的cookie,不同的浏览器有不同的处理方式)、

安全标志:(指定后,cookie只有在使用SSL连接时才发送到服务器(HTTPS))。

输入用户名密码登录网站后,之后再打开网站很多情况下就直接进去了,这个时候用到的一个机制就是Cookie。

二、Session(会话) :存储在服务端的一个数据结构。

Session 是一种HTTP存储机制,目的是为无状态的HTTP提供的持久机制。Session工作原理:

当用户第一次登陆后,客户端浏览器将用户信息发送给服务器,服务器使用Session为该用户创建一个SessionId(随机产生的字串,每个人的都不同)及保存Session内容(用户基础信息、权限信息、用户机构信息、固定变量等,这个数据可以保存在集群、数据库、文件中,用于跟踪用户的状态等),并在响应内容(Cookie)中将该SessionId一并返回给浏览器,浏览器再将这些数据保存再本地,当用户再次发送请求时,浏览器会自动把上次请求存储的Cookie数据自动携带给服务器,服务器接收到请求信息后,会通过浏览器请求的数据中的SessionId来查找该客户的状态就可以了。

Session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,并维护该Session。为防止内存溢出,服务器会把长时间内没有活跃的Session从内存删除。这个时间就是Session的超时时间。如果超过了超时时间没访问过服务器,Session就自动失效了。

这种用户信息存储方式相对cookie来说更安全,可是session有一个缺陷:如果web服务器做了负载均衡,那么下一个操作请求到了另一台服务器的时候session会丢失。

三、Token(令牌):用户身份验证方式

当客户端第一次访问服务端,服务端会根据传过来的唯一标识userId,运用一些算法,并加上密钥,生成一个Token,然后通过BASE64编码一下之后将这个Token返回给客户端,客户端将Token保存起来(可以通过数据库或文件形式保存本地)。下次请求时,客户端只需要带上Token,服务器收到请求后,会用相同的算法和密钥去验证Token和有效期。

最简单的Token组成:uid(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名,由Token的前几位+盐以哈希算法压缩成一定长的十六进制字符串,可以防止恶意第三方拼接Token请求服务器)。

使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录。大概的流程是这样的:

1.客户端使用用户名跟密码请求登录;
2.服务端收到请求,去验证用户名与密码;
3.验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端;
4.客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者数据库里;
5.客户端每次向服务端请求资源的时候需要带着服务端签发的 Token;
6.服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据,失败则返回错误信息,让他重新登录。

总结:

作为身份认证token安全性比session好,因为每个请求都有表明还能防止监听及重放攻击,而session就必须靠链路层来保障通讯安全。比如:如果你需要实现有状态的会话,仍然可以增加session来在服务器端保存一些状态。Session 认证只是简单的把User 信息存储到Session 里(有此SID即认为有此User的全部权利),因为SID 的不可预测性,暂且认为是安全的。而Token ,如果指的是OAuth Token 或类似的机制的话,提供的是"认证" 和"授权" ,认证是针对用户,授权是针对App 。其目的是让某App有权利访问某用户的信息,这里的 Token是唯一的,不可以转移到其它 App上,也不可以转到其它用户上。所以简单来说,如果你的用户数据可能需要和第三方共享,或者允许第三方调用 API 接口,就用 Token 。如果永远只是自己的网站,自己的 App,用什么就无所谓了。

Token就是令牌,比如你授权(登录)一个程序时,他就是个依据,判断你是否已经授权该软件;

Cookie就是写在客户端的一个txt文件,里面包括你登录信息之类的,这样你下次在登录某个网站,就会自动调用Cookie自动登录用户名;

Session和Cookie差不多,只是Session是写在服务器端的文件,也需要在客户端写入Cookie文件,但是文件里是你的浏览器编号.

Session的状态是存储在服务器端,客户端只有session id;而Token的状态是存储在客户端。

Cookie是不允许垮域访问的,但是token是支持的(前提是传输的用户认证信息通过HTTP头传输)。

互联网服务离不开用户认证。一般流程是下面这样:

1、用户向服务器发送用户名和密码。

2、服务器验证通过后,在当前对话(session)里面保存相关数据,比如用户角色、登录时间等等。

3、服务器向用户返回一个 session_id,写入用户的 Cookie。

4、用户随后的每一次请求,都会通过 Cookie,将 session_id 传回服务器。

5、服务器收到 session_id,找到前期保存的数据,由此得知用户的身份。

这种模式的扩展性不好:单机是没有问题,如果是服务器集群或者是跨域的服务导向架构,就要求 session 数据共享,每台服务器都能够读取 session。

一种解决方案是: session 数据持久化,写入数据库或别的持久层。各种服务收到请求后,都向持久层请求数据。这种方案工程量比较大,持久层万一挂了,就会单点失败。

另一种方案是:服务器索性不保存 session 数据了,所有数据都保存在客户端,每次请求都发回服务器。JWT 就是这种方案的一个代表。

JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案 :

JWT 的原理是,服务器认证以后,生成一个 JSON 对象,发回给用户,就像下面这样。

{
"姓名": "张三",
"角色": "管理员",
"到期时间": "2018年7月1日0点0分"
}
以后,用户与服务端通信的时候,都要发回这个 JSON 对象。服务器完全只靠这个对象认定用户身份。为了防止用户篡改数据,服务器在生成这个对象的时候,会加上签名(详见后文)。

JWT 的三个部分:Header(头部)、Payload(负载)、Signature(签名):

Header 部分是一个 JSON 对象,描述 JWT 的元数据,通常是下面的样子

{
"alg": "HS256",   // alg属性表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256)
"typ": "JWT"       // typ属性表示这个令牌(token)的类型(type)
}

Payload 部分也是一个 JSON 对象,用来存放实际需要传递的数据。注意,JWT 默认是不加密的,任何人都可以读到,所以不要把秘密信息放在这个部分。

Signature 部分是对前两部分的签名,防止数据篡改。
首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。
算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户。

后续继续深入学习。。。

猜你喜欢

转载自www.cnblogs.com/java-1230/p/10288878.html