酷代码 AI
菜单
全部AI  /  热门  /  AI写代码神器
服务商

token是什么?和session、cookie相比,使用场景有什么区别?

<p>在Web开发领域,相信大家对于Cookie和Session都很熟悉,Cookie和Session都是会话保持技术的解决方案。随着技术的发展,Token机制出现在我们面前,不过很多开发者对于Token和Cookie、Session的区别及使用场景分辨不清。</p><h1>Cookie和Session的用途</h1><p>要知道我们访问网站都是通过HTTP协议或HTTPS协议来完成的,<span style="font-weight: bold;">HTTP协议它本身是无状态的协议</span>(即:服务器无法分辨哪些请求是来源于同个客户)。而业务层面会涉及到客户端与服务器端的交互(同网站下多个页面间能共享数据),此时服务器端必须要保持会话状态,这样才能进行用户身份的鉴别。<br/></p><p>由于HTTP无状态的特性,如果要实话客户端和服务器端的会话保持,那就需要其它机制来实现,于是Cookie和Session应运而生。</p><p></p><p>通常情况下,<span style="font-weight: bold;">Session和Cookie是搭配在一起使用的</span>。</p><h1>Token是什么</h1><p>上面说到的Session和Cookie机制来保持会话,会存在一个问题:客户端浏览器只要保存自己的SessionID即可,而<span style="font-weight: bold;">服务器却要保存所有用户的Session信息,这对于服务器来说开销较大,而且不利用服务器的扩展</span>(比如服务器集群时,Session如何同步存储就是个问题)!</p><p>于是有人思考,如果把Session信息让客户端来保管而且无法伪造不就可以解决这个问题了?进而有了Token机制。</p><p><span style="font-weight: bold;">Token俗称为“令牌”</span>,它的构成是:</p><ul><li><p>uid:<span style="font-weight: bold;">用户唯一身份标识</span></p></li><li><p>timestamp:<span style="font-weight: bold;">当前时间戳</span></p></li><li><p>sign:<span style="font-weight: bold;">签名字符串</span>,防止第三方伪造数据;签名密钥是存储在服务器端的,其它人无法知道</p></li><li><p>其它附加参数。</p></li></ul><h1>Token机制下的认证流程</h1><p><span style="font-weight: bold;">Token机制其实和Cookie机制极其相似</span>,主要有以下流程:<br/></p><p>1、用户登录进行身份认证,认证成功后服务器端生成Token返回给客户端;</p><p>2、客户端接收到Token后保存在客户端(可保存在Cookie、LocalStorage、SessionStorage中);</p><p>3、客户端再次请求服务器端时,将Token作为请求头放入Headers中;</p><p>4、服务器端接收请求头中的Token,将用户参数按照既定规则再进行一次签名,两次签名若一致则认为成功,反之数据存在篡改请求失败。</p><p><br/>(生成签名示例图)<br/></p><p>(验证签名示例图)</p><h1>Token与Cookie+Session的区别</h1><p>Cookie其实也充当的是令牌作用,但它是“有状态”的;<span style="font-weight: bold;">而Token令牌是无状态的,更利于分布式部署。</span></p><p><span style="font-weight: bold;"><br/></span></p><blockquote><span style="font-weight: bold;">以上就是我的观点,对于这个问题大家是怎么看待的呢?欢迎在下方评论区交流 ~ 我是科技领域创作者,十年互联网从业经验,欢迎关注我了解更多科技知识!</span></blockquote><p><span style="font-weight: bold;"> </span></p><p><h1>session和cookie</h1><p>在讲Token之前,先简单说说什么是session和cookie。</p><ul><li><p>首先要知道HTTP请求是无状态的,也就是不知道这一次的请求和上一次请求是否有关系,比如我们登录一个系统的时候,验证用户名密码之后,打开系统各个页面的时候就不需要再进行登录操作了,直到我们主动退出登录或超时退出登录;这里为了避免访问每个都登录一下,就要用到session、cookie。<br/></p></li><li><p>cookie是在客户端(浏览器)保存用户信息的一种机制;而且每种浏览器存储大小会有一些差异,一般不超过4KB;<br/></p></li><li><p>session是在服务端保存,可以用于记录客户状态,比如我们经常会用session保存客户的基本信息、权限信息等;用户第一次登录之后,服务器就会创建一个session,浏览器再次访问时,只需要从该session中查找该客户的信息就可以了。<br/></p></li></ul><p></p><h1>Token</h1><p></p><p>但是这里会有个问题,<span style="font-weight: bold;">服务器要保存所有用户的session信息,开销会很大,如果在分布式的架构下,就需要考虑session共享的问题,需要做额外的设计和开发</span>,例如把session中的信息保存到Redis中进行共享;所以因为这个原因,有人考虑这些信息是否可以让客户端保存,可以保存到任何地方,并且保证其安全性,于是就有了Token。</p><p>Token是服务端生成的一串字符串,可以看做客户端进行请求的一个令牌。</p><ul><li><p>当客户端第一次访问服务端,服务端会根据传过来的唯一标识userId,运用一些加密算法,生成一个Token,客户端下次请求时,只需要带上Token,服务器收到请求后,会验证这个Token。<br/></p></li><li><p>有些公司会建设<span style="font-weight: bold;">统一登录系统(单点登录)</span>,客户端先去这个系统获取Token,验证通过再拿着这些Token去访问其他系统;<span style="font-weight: bold;">API Gateway</span>也可以提供类似的功能,我们公司就是这样,客户端接入的时候,先向网关获取Token,验证通过了才能访问被授权的接口,并且一段时间后要重新或者Token。</p></li></ul><p></p><h1>基于Token的认证流程</h1><p></p><p>整体的流程是这样的:</p><ol><li><p>客户端使用用户名、密码做身份验证;<br/></p></li><li><p>服务端收到请求后进行身份验证;(也可能是统一登录平台、网关)<br/></p></li><li><p>验证成功后,服务端会签发一个Token返回给客户端;<br/></p></li><li><p>客户端收到Token以后可以把它存储起来(可以放在);每次向服务端发送请求的时候,都要带着Token;<br/></p></li><li><p>Token会有过期时间,过期后需要重新进行验证;<br/></p></li><li><p>服务端收到请求,会验证客户端请求里面的Token,验证成功,才会响应客户端的请求;<br/></p></li></ol><p></p><p></p><h1></h1><ul><li><p>cookie:保存在浏览器种,有大小限制,有状态;<br/></p></li><li><p>session:保存在服务器中,服务器有资源开销,分布式、跨系统不好实现;<br/></p></li><li><p>Token:客户端可以将Token保存到任何地方,无限制,无状态,利于分布式部署。<br/></p></li></ul><h1>希望我的回答,能够帮助到你!我将持续分享Java开发、架构设计、程序员职业发展等方面的见解,希望能得到你的关注。</h1><p></p></p><p><p><span style="font-weight: bold;">由Session到Token的身份验证演变过程理解Session、Cookie、Token</span></p><div><div><p></p></div><p>本文将从Web应用 由传统身份验证到基于Token的身份验证的演变过程的角度,介绍Session、Cookie、Token。</p><p>很久以前,Web 应用基本用作文档的浏览,如网络黄页。既然仅仅是浏览,因此服务器不需要记录具体用户在某一段时间里都浏览了哪些文档,每次请求都是一个新的HTTP协议,对服务器来说都是全新的。</p></div><hr/><div><h1>基于Session的身份验证</h1><p>随着交互式Web应用的兴起,比如,购物等需要登录的网站。引出了一个新的问题,那就是要记录哪些用户登录了系统进行了哪些操作,即要管理会话(什么是会话?简单的讲如果用户需要登录,那么就可以简单的理解为会话,如果不需要登录,那么就是简单的连接。),比如,不同用户将不同商品加入到购物车中, 也就是说必须把每个用户区分开。因为HTTP请求是无状态的,所以想出了一个办法,那就是给每个用户配发一个会话标识(Session id),简单的讲就是一个既不会重复,又不容易被找到规律以仿造的随机字符串,使得每个用户的收到的会话标识都不一样, 每次用户从客户端向服务端发起HTTP请求的时候,把这个字符串给一并发送过来, 这样服务端就能区分开谁是谁了,至于客户端(浏览器)如何保存这个“身份标识”,一般默认采用 Cookie 的方式,这个会话标识(Session id)会存在客户端的Cookie中。</p><p>虽然这样解决了区分用户的问题,但又引发了一个新的问题,那就是每个用户(客户端)只需要保存自己的会话标识(Session id),而服务端则要保存所有用户的会话标识(Session id)。 如果访问服务端的用户逐渐变多, 就需要保存成千上万,甚至几千万个,这对服务器说是一个难以接受的开销 。 再比如,服务端是由2台服务器组成的一个集群, 小明通过服务器A登录了系统, 那session id会保存在服务器A上, 假设小明的下一次请求被转发到服务器B怎么办? 服务器B可没有小明 的 session id。</p><p>可能会有人讲,如果使小明登录时,始终在服务器A上进行登录(sticky session),岂不解决了这个问题?那如果服务器A挂掉怎么办呢? 还是会将小明的请求转发到服务器B上。</p><p>如此一来,那只能做集群间的 session 复制共享了, 就是把 session id 在两个机器之间进行复制,如下图,但这对服务器的性能和内存提出了巨大的挑战。</p><div><p></p></div><p>又想到如果将所有用户的Session集中存储呢,也就想到了缓存服务Memcached——由于 Memcached 是分布式的内存对象缓存系统,因此可以用来实现 Session 同步。把session id 集中存储到一台服务器上, 所有的服务器都来访问这个地方的数据, 如此就避免了复制的方式, 但是这种“集万千宠爱于一身”使得又出现了单点故障的可能, 就是说这个负责存储 session 的服务器挂了, 所有用户都得重新登录一遍, 这是用户难以接受的。</p><div><p></p></div><p>那么索性存储Session的服务器也搞成集群,增加其可靠性,避免单点故障,但不管如何,Session 引发出来的问题层出不穷。</p><p>于是有人就在思考, 为什么服务端必须要保存这session呢, 只让每个客户端去保存不行吗?可是服务端如果不保存这些session id ,又将如何验证客户端发送的 session id 的确是服务端生成的呢? 如果不验证,服务端无法判断是否是合法登录的用户,对,这里的问题是验证, session 只是解决这个验证问题的而产生的一个解决方案,是否还有其它方案呢?</p></div><hr/><div><h1>基于Token 的身份验证</h1><p>例如, 小明已经登录了系统,服务端给他发一个令牌(Token), 里边包含了小明的 user id, 后续小明再次通过 Http 请求访问服务器的时候, 把这个 Token 通过 Http header 带过来不就可以了。</p><p>服务端需要验证 Token是自己生成的,而非伪造的。假如不验证任何人都可以伪造,那么这个令牌(token)和 session id没有本质区别,如何让别人伪造不了?那就对数据做一个签名(Sign)吧, 比如说服务端用 HMAC-SHA256 加密算法,再加上一个只有服务端才知道的密钥, 对数据做一个签名, 把这个签名和数据一起作为 Token 发给客户端, 客户端收到 Token 以后可以把它存储起来,比如存储在 Cookie 里或者 Local Storage 中,由于密钥除了服务端任何其他用户都不知道, 就无法伪造令牌(Token)。</p><div><p></p></div><p>如此一来,服务端就不需要保存 Token 了, 当小明把这个Token发给服务端时,服务端使用相同的HMAC-SHA256 算法和相同的密钥,对数据再计算一次签名, 和 Token 中的签名做个对比, 如果相同,说明小明已经登录过了, 即验证成功。若不相同, 那么说明这个请求是伪造的。</p><div><p></p></div><p>这样一来, 服务端只需要生成 Token,而不需要保存Token, 只是验证Token就好了 ,也就实现了时间换取空间(CPU计算时间换取session 存储空间)。没了session id 的限制, 当用户访问量增大, 直接加机器就可以轻松地做水平扩展,也极大的提高了可扩展性。</p></div></p><p><span style="font-weight: bold;">Token顾名思义就是令牌、凭证、钥匙</span>。只有这把钥匙,你才能打开门。token一般都是服务端生成,比如一个web系统,用户登录的时候,服务端校验用户名密码通过以后,会生成一个token,同时会生成refreshToken和一个过期时间。然后将refreshToken和token返回给客户端。客户端会将token保存下来。后续所有的请求都会携带这个token。服务端会判断当前token是否存在已经是否过期。如果token不存在或者过期就会拒绝本次请求。如果token过期怎么办,就用refreshToken刷新时间。当然这里可能还有别的方案。比如只生成token,每次请求的时候都刷新过期时间。如果长时间没有刷新过期时间,那token就会过期。</p><hr/><p>session就是回话,这是服务端的一种操作。当你第一次访问一个web网站的时候,服务端会生成一个session,并有一个sessionid和他对应。这个session是存储到内存中的,你可以向这个session中写入信息,比如当前登录用户的信息。sessionid会被返回到客户端,客户端一般采用cookie来保存。当然这个cookie不用人为写入。用tomcat容器来举个例子。<span style="font-weight: bold;">当后端调用HttpServletRequest对象的getSession的方法的时候,tomcat内部会生成一个jsessonid(tomcat sessionid的叫法)。这个jsessonid会随本次请求返回给客户端。响应头信息</span></p><blockquote> HTTP/1.1 200 OK<br/> Set-Cookie: JSESSIONID=xxxxxxxxxxxxxxxxxxx</blockquote><p>这个jessionid就会写到cookie中。之后jessionid就会通过cookie传递到服务端。</p><p></p><p></p><p>这里我们就会很清楚了,<span style="font-weight: bold;">session的数据是存储到内存中。那问题就来了,如果我们的服务是分布式部署,有多台机器的话,可能我们第一次登陆的时候,我们把用户的信息存储到了session,但是后面的请求到了B机器上,那B机器是获取不到用户的session的。另外就是session存储在内存中,那服务器重启,session就丢失了,这就是他的弊端。现在有一些技术,例如session共享、iphash、session持久等也可以解决上述问题</span>。</p><hr/><div>cookie是浏览器的一种策略。上述讲到了sessionid就是存储在cookie中的。我们知道http协议是无状态的,cookie就是用来解决这个问题的。cookie中可以用来保存服务端返回的一些用户信息的,例如前文提到的token、sessionid。每一次的请求,都会携带这些cookie。服务端从请求头中取到cookie中的信息,就可以识别本次请求的来源,这样,http是不是就变成有状态的了。</div><div><span style="font-weight: bold;">这里说几点cookie注意事项。</span></div><p>cookie是浏览器的一种策略。上述讲到了sessionid就是存储在cookie中的。我们知道http协议是无状态的,cookie就是用来解决这个问题的。cookie中可以用来保存服务端返回的一些用户信息的,例如前文提到的token、sessionid。每一次的请求,都会携带这些cookie。服务端从请求头中取到cookie中的信息,就可以识别本次请求的来源,这样,http是不是就变成有状态的了。</p><p>这里说几点cookie注意事项。</p><p><span style="font-weight: bold;">1、cookie存放在客户端,所以是不安全的。人为可以清除</span></p><p><span style="font-weight: bold;">2、cookie有过期时间设定。如果不设置过期时间,说明这个cookie就是当前浏览器的会话时间,浏览器关了,cookie 就存在了。如果有过期时间,cookie就会存储到硬盘上,浏览器关闭不影响cookie。下次打开浏览器,cookie还存在</span></p><p><span style="font-weight: bold;">3、cookie有大小的限制,4KB。</span></p><p>这个问题,网上有很多的答案,相信都看过了,估计也没有看明白。所以我就不去网上复制了,用自己的话,尽量说通俗,说重点。</p><p>cookie和session实际上是同一套认证流程,相辅相成。session保存在服务器,cookie保存在客户端。最常见的做法就是客户端的cookie仅仅保存一个sessionID,这个sessionID是一个毫无规则的随机数,由服务器在客户端登录通过后随机生产的。往后,客户端每次访问该网站都要带上这个由sessionID组成的cookie。服务器收到请求,首先拿到客户端的sessionID,然后从服务器内存中查询它所代表的客户端(用户名,用户组,有哪些权限等)。</p><p>与token相比,这里的重点是,服务器必须保存sessionID以及该ID所代表的客户端信息。这些内容可以保存在内存,也可以保存到数据库(通常是内存数据库)。</p><p>而token则可以服务器完全不用保存任何登录信息。</p><p>token的流程是这样的。客户端登录通过后,服务器生成一堆客户端身份信息,包括用户名、用户组、有那些权限、过期时间等等。另外再对这些信息进行签名。之后把身份信息和签名作为一个整体传给客户端。这个整体就叫做token。之后,客户端负责保存该token,而服务器不再保存。客户端每次访问该网站都要带上这个token。服务器收到请求后,把它分割成身份信息和签名,然后验证签名,若验证成功,就直接使用身份信息(用户名、用户组、有哪些权限等等)。</p><p>可以看出,相对于cookie/session机制,token机制中,服务器根本不需要保存用户的身份信息(用户名、用户组、权限等等)。这样就减轻了服务器的负担。</p><p>我们举个例来说,假如目前有一千万个用户登录了,在访问不同的网页。如果用cookie/session,则服务器内存(或内存数据库)中要同时记录1千万个用户的信息。每次客户端访问一个页面,服务器都要从内存中查询出他的登录信息。而如果用token,则服务器内存中不记录用户登录信息。它只需要在收到请求后,直接使用客户端发过来的登录身份信息。</p><p>可以这么说,<span style="font-weight: bold;">cookie/session是服务器说客户端是谁,客户端才是谁。而token是客户端说我(客户端)是谁,我就是谁</span>。当然了,token是有签名机制的。要是客户端伪造身份,签名通不过。这个签名算法很简单,就是将客户端的身份信息加上一个只有服务器知道的盐值(不能泄露),然后进行md5散列算法(这里只是简化,方便理解,实际细节要稍复杂一些)。</p><p>cookie/session在单服务器,单域名时比较简单,否则的话,就要考虑如何将客户端的session保存或同步到多个服务器。还要考虑一旦宕机,内存中的这些信息是否会丢失。token因为服务器不保存用户身份,就不存在这个问题。这是token的优点。</p><p>token因为服务器不保存用户身份信息,一切都依赖当初那个签名。所以存在被盗用的风险。也就是说一旦盗用,服务器可能毫无办法,因为它只认签名算法。而session机制,服务器看谁不爽,可以随时把他踢出(从内存中删掉)。正是因为如此,token高度依赖过期时间。过期时间不能太长。过期短,可以减少被盗用的风险。</p><p>除了上面所说的,我个人认为,如果开发的系统足够小,倾向于使用cookie/session。如果系统同时登录用户多,集群服务器多,有单点登录需求,则倾向于使用token。</p> [2023-10-04 12:32:26 | AI写代码神器 | 9594点数解答]

相关提问