欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

cookie、session与token之间的关系

程序员文章站 2022-04-13 14:40:12
cookie、session与token之间的关系 token 令牌,是用户身份的验证方式。 最简单的token组成:uid(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名)。...
cookie、session与token之间的关系

token

令牌,是用户身份的验证方式。

最简单的token组成:uid(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名)。

对token认证的五点认识

一个token就是一些信息的集合; 在token中包含足够多的信息,以便在后续请求中减少查询的几率; 服务端需要对cookie和http authrorization header进行token信息的检查; 基于上一点,你可以用一套token认证代码来面对类客户端和非浏览器类客户端; 因为token是被签名的,所以我们可以认为一个可以解码认证通过的token是由我们发放的,其中带的信息是合法有效的;

session

会话,代表服务器与浏览器的一次会话过程,这个过程是连续的,也可以时断时续。

cookie中存放着一个sessionid,请求时会发送这个id;

session因为请求(request对象)而产生;

session是一个容器,可以存放会话过程中的任何对象;

session的创建与使用总是在服务端,浏览器从来都没有得到过session对象;

session是一种http存储机制,目的是为武装的http提供持久机制。

cookie

储存在用户本地终端上的数据,服务器生成,发送给浏览器,下次请求统一网站给服务器。

cookie与session区别

cookie数据存放在客户端上,session数据放在服务器上;

cookie不是很安全,且保存数据有限;

session一定时间内保存在服务器上,当访问增多,占用服务器性能。

session与token

作为身份认证,token安全行比session好;

session 认证只是简单的把user 信息存储到session 里,因为sid 的不可预测性,暂且认为是安全的。这是一种认证手段。 而token ,如果指的是oauth token 或类似的机制的话,提供的是 认证 和 授权 ,认证是针对用户,授权是针对app 。其目的是让 某app有权利访问 某用户 的信息。

token与cookie

cookie是不允许垮域访问的,但是token是支持的, 前提是传输的用户认证信息通过http头传输;

token就是令牌,比如你授权(登录)一个程序时,他就是个依据,判断你是否已经授权该软件;cookie就是写在客户端的一个txt文件,里面包括你登录信息之类的,这样你下次在登录某个网站,就会自动调用cookie自动登录用户名;session和cookie差不多,只是session是写在服务器端的文件,也需要在客户端写入cookie文件,但是文件里是你的浏览器编号.session的状态是存储在服务器端,客户端只有session id;而token的状态是存储在客户端。

http协议与状态保持:http是一个无状态协议

1. 实现状态保持的方案:

1)修改http协议,使得它支持状态保持(难做到)

2)cookies:通过客户端来保持状态信息

cookie是服务器发给客户端的特殊信息

cookie是以文本的方式保存在客户端,每次请求时都带上它

3)session:通过服务器端来保持状态信息

session是服务器和客户端之间的一系列的交互动作

服务器为每个客户端开辟内存空间,从而保持状态信息

由于需要客户端也要持有一个标识(id),因此,也要求服务器端和客户端传输该标识,

标识(id)可以借助cookie机制或者其他的途径来保存

2. cookie机制

1)cookie的基本特点

cookie保存在客户端

只能保存字符串对象,不能保存对象类型

需要客户端浏览器的支持:客户端可以不支持,浏览器用户可能会禁用cookie

2)采用cookie需要解决的问题

cookie的创建

通常是在服务器端创建的(当然也可以通过javascript来创建)

服务器通过在http的响应头加上特殊的指示,那么浏览器在读取这个指示后就会生成相应的cookie了

cookie存放的内容

业务信息("key","value")

过期时间

域和路径

浏览器是如何通过cookie和服务器通信?

通过请求与响应,cookie在服务器和客户端之间传递

每次请求和响应都把cookie信息加载到响应头中;依靠cookie的key传递。

3. cookie

1)cookie类

servlet api封装了一个类:javax.servlet.http.cookie,封装了对cookie的操作,包括:

public cookie(string name, string value) //构造方法,用来创建一个cookie

httpservletrequest.getcookies() //从http请求中可以获取cookies

httpservletresponse.addcookie(cookie) //往http响应添加cookie

public int getmaxage() //获取cookie的过期时间值

public void setmaxage(int expiry) //设置cookie的过期时间值

2)cookie的创建

cookie是一个名值对(key=value),而且不管是key还是value都是字符串

如: cookie visit = new cookie("visit", "1");

3)cookie的类型——过期时间

会话cookie

cookie.setmaxage(-1);//负整数

保存在浏览器的内存中,也就是说关闭了浏览器,cookie就会丢失

普通cookie

cookie.setmaxage(60);//正整数,单位是秒

表示浏览器在1分钟内不继续访问服务器,cookie就会被过时失效并销毁(通常保存在文件中)

注意:

cookie.setmaxage(0);//等价于不支持cookie;

4. session机制

每次客户端发送请求,服务断都检查是否含有sessionid。

如果有,则根据sessionid检索出session并处理;如果没有,则创建一个session,并绑定一个不重复的sessionid。

1)基本特点

状态信息保存在服务器端。这意味着安全性更高

通过类似与hashtable的数据结构来保存

能支持任何类型的对象(session中可含有多个对象)

2)保存会话id的技术(1)

cookie

这是默认的方式,在客户端与服务器端传递jseesionid

缺点:客户端可能禁用cookie

表单隐藏字段

在被传递回客户端之前,在 form 里面加入一个hidden域,设置jseesionid:

 

cookie、session与token之间的关系

 

url重写

直接在url后附加上session id的信息

httpservletresponse对象中,提供了如下的方法:

encodeurl(url); //url为相对路径

5. session编程

1)httpsession接口

servlet api定义了接口:javax.servlet.http.httpsession, servlet容器必须实现它,用以跟踪状态。

当浏览器与servlet容器建立一个http会话时,容器就会通过此接口自动产生一个httpsession对象

2)获取session

httpservletrequest对象获取session,返回httpsession:

request.getsession(); //表示如果session对象不存在,就创建一个新的会话

request.getsession(true); //等价于上面这句;如果session对象不存在,就创建一个新的会话

request.getsession(false); //表示如果session对象不存在就返回 null,不会创建新的会话对象

3)session存取信息

session.setattribute(string name,object o) //往session中保存信息

object session.getattribute(string name) //从session对象中根据名字获取信息

4)设置session的有效时间

public void setmaxinactiveinterval(int interval)

设置最大非活动时间间隔,单位秒;

如果参数interval是负值,表示永不过时。零则是不支持session。

通过配置web.xml来设置会话超时,单位是分钟

1

允许两种方式并存,但前者优先级更高

5)其他常用的api

httpsession.invalidate() //手工销毁session

boolean httpsession.isnew() //判断session是否新建

如果是true,表示服务器已经创建了该session,但客户端还没有加入(还没有建立会话的握手)

httpsession.getid() //获取session的id

6). 两种状态跟踪机制的比较

cookie session

保持在客户端 保存在服务器端

只能保持字符串对象 支持各种类型对象

通过过期时间值区分cookie的类型 需要sessionid来维护与客户端的通信

会话cookie——负数 cookie(默认)

普通cookie——正数 表单隐藏字段

不支持cookie——0 url重写

json web token(缩写 jwt)是目前最流行的跨域认证解决方案

一、跨域认证的问题

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

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

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

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

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

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

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

举例来说,a 网站和 b 网站是同一家公司的关联服务。现在要求,用户只要在其中一个网站登录,再访问另一个网站就会自动登录,请问怎么实现?

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

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

二、jwt 的原理

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

{

"姓名": "张三",

"角色": "管理员",

"到期时间": "2018年7月1日0点0分"

}

以后,用户与服务端通信的时候,都要发回这个 json 对象。服务器完全只靠这个对象认定用户身份。为了防止用户篡改数据,服务器在生成这个对象的时候,会加上签名(详见后文)。

服务器就不保存任何 session 数据了,也就是说,服务器变成无状态了,从而比较容易实现扩展。

三、jwt 的数据结构

实际的 jwt 大概就像下面这样。

它是一个很长的字符串,中间用点(.)分隔成三个部分。注意,jwt 内部是没有换行的,这里只是为了便于展示,将它写成了几行。

jwt 的三个部分依次如下。

header(头部) payload(负载) signature(签名)

写成一行,就是下面的样子。

header.payload.signature

下面依次介绍这三个部分。

3.1 header

header 部分是一个 json 对象,描述 jwt 的元数据,通常是下面的样子。

{

"alg": "hs256",

"typ": "jwt"

}

上面代码中,alg属性表示签名的算法(algorithm),默认是 hmac sha256(写成 hs256);typ属性表示这个令牌(token)的类型(type),jwt 令牌统一写为jwt。

最后,将上面的 json 对象使用 base64url 算法(详见后文)转成字符串。

3.2 payload

payload 部分也是一个 json 对象,用来存放实际需要传递的数据。jwt 规定了7个官方字段,供选用。

iss (issuer):签发人 exp (expiration time):过期时间 sub (subject):主题 aud (audience):受众 nbf (not before):生效时间 iat (issued at):签发时间 jti (jwt id):编号

除了官方字段,你还可以在这个部分定义私有字段,下面就是一个例子。

{

"sub": "1234567890",

"name": "john doe",

"admin": true

}

注意,jwt 默认是不的,任何人都可以读到,所以不要把秘密信息放在这个部分。

这个 json 对象也要使用 base64url 算法转成字符串。

3.3 signature

signature 部分是对前两部分的签名,防止数据篡改。

首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 header 里面指定的签名算法(默认是 hmac sha256),按照下面的公式产生签名。

hmacsha256(

base64urlencode(header) + "." +

base64urlencode(payload),

secret)

算出签名以后,把 header、payload、signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户。

3.4 base64url

前面提到,header 和 payload 串型化的算法是 base64url。这个算法跟 base64 算法基本类似,但有一些小的不同。

jwt 作为一个令牌(token),有些场合可能会放到 url(比如 api.example.com/token=xxx)。base64 有三个字符+、/和=,在 url 里面有特殊含义,所以要被替换掉:=被省略、+替换成-,/替换成_。这就是 base64url 算法。

四、jwt 的使用方式

客户端收到服务器返回的 jwt,可以储存在 cookie 里面,也可以储存在 localstorage。

此后,客户端每次与服务器通信,都要带上这个 jwt。你可以把它放在 cookie 里面自动发送,但是这样不能跨域,所以更好的做法是放在 http 请求的头信息authorization字段里面。

authorization: bearer

另一种做法是,跨域的时候,jwt 就放在 post 请求的数据体里面。

五、jwt 的几个特点

(1)jwt 默认是不加密,但也是可以加密的。生成原始 token 以后,可以用密钥再加密一次。

(2)jwt 不加密的情况下,不能将秘密数据写入 jwt。

(3)jwt 不仅可以用于认证,也可以用于交换信息。有效使用 jwt,可以降低服务器查询数据库的次数。

(4)jwt 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 jwt 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。

(5)jwt 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,jwt 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。

(6)为了减少盗用,jwt 不应该使用 http 协议明码传输,要使用 https 协议传输。