登录功能的实现、cookie和session、localStorage和sessionStorage、IndexedDB、JWT汇总

2,186 阅读12分钟

登录功能的实现

  • Cookie + Session 登录

    • Cookie + Session用户向服务器发送用户名和密码,服务器通过验证后,在当前对话(session)里面保存相关数据(比如用户角色,登录时间等),服务器向用户返回一个session_id,写入cookie,用户随后的每一次请求都会通过cookie,将session_id传回服务器,服务器收到session_id,找到前期保存的数据,由此得知用户的身份。
  • Token 登录

    • Token 是通过服务端生成的一串字符串,以作为客户端请求的一个令牌。当第一次登录后,服务器会生成一个 Token 并返回给客户端,客户端后续访问时,只需带上这个 Token 即可完成身份认证。
  • SSO 单点登录

    • 单点登录是指在同一帐号平台下的多个应用系统中,用户只需登录一次,即可访问所有相互信任的应用系统。本质就是在多个应用系统中共享登录状态。用户首次访问时,需要在认证中心登录;会创建授权码 ticket;当信任的其他系统时,认证中心验证账号密码,如果登录还有效,会重定向并带上授权码 ticket,就可以验证登录了。
  • OAuth 第三方登录

可以看这篇:前端常见登录实现方案 + 单点登录方案

cookie和session

HTTP协议是一种无状态协议,即每次服务端接收到客户端的请求时,都是一个全新的请求,服务器并不知道客户端的历史请求记录;SessionCookie的主要目的就是为了弥补HTTP的无状态特性。

cookie是什么?

cookie是服务器发送到Web浏览器的一小块数据,服务器发送到浏览器的Cookie,浏览器会进行存储,并与下一个请求一起发送到服务器,用于判断请求是否来自同一个浏览器,例如用户保持登录状态。

cookie的属性

属性说明
name=value键值对,设置 Cookie 的名称及相对应的值,都必须是字符串类型 - 如果值为 Unicode 字符,需要为字符编码。 如果值为二进制数据,则需要使用 BASE64 编码。
domain该字段为可以访问此cookie的域名,即cookie在哪个域有效,默认是当前域名
sizecookie的大小(不超过4kb)
pathcookie的有效路径,默认是'/'DomainPath标识共同定义了Cookie的作用域:即 Cookie应该发送给哪些URL
maxAgeMax-Age有效期的时间戳(服务器返回的时间,和客户端可能存在误差),默认为-1,页面关闭立即失效。优先级高于expires
expires过期时间,在设置的某个时间点后该 cookie 就会失效。 一般浏览器的 cookie 都是默认储存的,当关闭浏览器结束这个会话的时候,这个 cookie 也就会被删除
secure标记为SecureCookie只应通过被HTTPS协议加密过的请求发送给服务端,可以保护Cookie在浏览器和Web服务器间的传输过程中不被窃取和篡改。
httpOnly设置为true时不允许通过脚本document.cookie去更改cookie值,也不可获取,能有效的防止xss攻击。但发送请求仍会携带cookie。
SameSite该属性可以让Cookie在跨站请求时不会被发送,用来防止CSRF攻击和用户追踪
  • SameSite的三个取值:
    • Strict:完全禁止第三方cookie,跨站点时,任何情况下都不会发送cookie。也就是说,只有当前网页的URL与请求目标一致,才会带上cookie
    • Lax: 大多数情况不发送第三方cookie,但导航到目标网址的get请求(链接,预加载请求,GET表单)除外。
    • None: 网站可以选择显式关闭SameSite属性,将其设为None。不过,前提是必须同时设置Secure属性(Cookie 只能通过 HTTPS 协议发送),否则无效。

F12查看cookie:

浏览器查看cookie

cookie安全

安全问题可以看我总结的这篇:前端安全—常见的攻击方式及防御方法

cookie跨域

跨域可以看这篇:九种跨域方法及原理

session是什么?

Session是保存在服务器记录客户状态的机制。客户端浏览器访问服务器的时候,服务器会为这次请求开辟一块内存空间,这个对象便是Session 对象,存储结构为 ConcurrentHashMap。Session 弥补了 HTTP 无状态特性,服务器可以利用 Session 存储客户端在同一个会话期间的一些操作记录。

session的创建

  • 用户向服务器发送用户名和密码
  • 服务器通过验证后,在当前对话(session)里面保存相关数据(比如用户角色,登录时间等)
  • 服务器向用户返回一个session_id,写入cookie
  • 用户随后的每一次请求都会通过cookie,将session_id传回服务器
  • 服务器收到session_id,找到前期保存的数据,由此得知用户的身份。

image.png SessionID 是连接 Cookie 和 Session 的一道桥梁,大部分系统也是根据此原理来验证用户登录状态。

cookie和session的区别

  • 储存方式:cookie是服务端产生,储存在客户端;session储存在服务端
  • 储存大小:单个cookie不超过4kb;session没有大小限制,但当访问过多,会占用过多的服务器资源
  • 安全性:session更安全
  • 储存内容:cookie只能保存字符串,以文本的方式;session通过类似hashtable的数据结构来储存,能支持任何数据类型
  • 使用方式
    • cookie机制:如果不在浏览器设置过期时间,cookie被保存在内存中,cookie生命周期随浏览器的关闭而结束。如果在浏览器中设置了cookie的过期时间,cookie被保存在硬盘中,关闭浏览器后,cookie数据仍然存在,知道过期时间才消失。
    • session机制:当服务器收到请求需要创建session对象时,首先会检查客户端请求中是否包含session_id,如果有,服务器将根据id返回对应的session对象。如果没有session_id,服务器会创建新的session对象,并把session_id在本次响应中返回给客户端。

cookie、localStorage和sessionStorage

HTML5提供了两种在客户端存储数据的新方法:localStorage和sessionStorage,挂载在window对象下。

webStorage是本地存储,数据不是由服务器请求传递的。从而它可以存储大量的数据,而不影响网站的性能。

Web Storage的目的是为了克服由cookie带来的一些限制,当数据需要被严格控制在客户端上时,无须持续地将数据发回服务器。比如客户端需要保存的一些用户行为或数据,或从接口获取的一些短期内不会更新的数据,我们就可以利用Web Storage来存储。

localStorage

生命周期是永久性的。localStorage存储的数据,以“键值对”的形式存在。即使关闭浏览器,也不会让数据消失,除非主动的去删除数据。如果想设置失效时间,需自行封装。localStorage 在所有同源窗口中都是共享的。

  • localstorage设置过期时间
    • localStorage只能存储字符,存入时将对象转为json字符串,读取时也要通过JSON.stringify解析
    • set(key, value, expired) 设置过期时间

可以看这篇:localstorage设置过期时间

sessionStorage

sessionStorage保存的数据用于浏览器的一次会话,当会话结束(关闭浏览器或者页面),数据被清空;SessionStorage的属性和方法与LocalStorage完全一样。

sessionStorage特别的一点在于,即便是相同域名下的两个页面,只要它们不在同一个浏览器窗口中打开,那么它们的 sessionStorage 内容便无法共享localStorage 在所有同源窗口中都是共享的; cookie也是在所有同源窗口中都是共享的。除了保存期限的长短不同,

cookie、localStorage和sessionStorage的区别

  • 共同点:都是保存在浏览器端,且都遵循同源策略。
  • 不同点:在于生命周期与作用域等不同 image.png

WebStorage 提供方法操作数据

sessionStorage和localStorage可使用的API都相同,其功能包括保存数据、读取数据、删除数据、得到索引的key值等。

  • setItem(key, value) : 保存数据,以键值对方式储存信息
  • getItem(key) : 获取数据,将键值传入,即可获取到对应的value值
  • removeItem(key) : 删除单个数据
  • clear() : 删除所有数据
  • key(index) : 允许获取一个指定位置的键值

若是 localStorage 存满了,再往里存东西,或者要存的东西超过了剩余容量,会发生什么?存满了怎么办?

存不进去并报错(QuotaExceededError) localStorage 会可以将第一次请求的数据直接存储到本地,这个相当于一个 5M 大小的针对于前端页面的数据库,相比于 cookie(4k) 可以节约带宽,但是这个却是只有在高版本的浏览器中才支持的。

但是一旦本地前端对数据存储要求比较高 比如聊天记录 等对缓存容积比较高的 比如超过5M 就要想别的办法了 比如优秀的indexDB

IndexedDB

IndexedDB是一个运行在浏览器上的非关系型数据库,储存空间大,用于客户端存储大量结构化数据(包括文件和blobs) 。IndexedDB是一个基于JavaScript的面向对象的数据库,可以存字符串,也可以存二进制数据,数据以"键值对"的形式保存,不能有重复,否则会报错。除非被清理,否则一直存在。

  • 键值对储存
  • 异步
  • 支持事务
  • 同源策略
  • 支持二进制储存

JWT(JSON Web Token)

互联网服务离不开用户认证。一般流程看上面session的创建

什么是Token?

  • Token的定义

    Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码。token其实说的更通俗点可以叫暗号,在一些数据传输之前,要先进行暗号的核对,不同的暗号被授权不同的数据操作。

  • 简单 token 的组成

    • uid(用户唯一的身份标识)
    • time(当前时间戳)
    • sign(签名,token 的前几位以哈希算法压缩成的一定长度的十六进制字符串)
  • token 的身份验证流程

    • 客户端使用用户名跟密码请求登录
    • 服务端收到请求,去验证用户名与密码
    • 客户端收到 token 以后,会把它存储起来,比如放在 cookie 里或者 localStorage
    • 客户端每次向服务端请求资源的时候需要带着服务端签发的 token
    • 服务端收到请求,然后去验证客户端请求里面带着的 token ,如果验证成功,就向客户端返回请求的数据 image.png
  • 使用Token的目的

    Token的目的是为了减少频繁的查询数据库,减轻服务器的压力。基于Token用户认证是一种服务器无状态的认证方式,服务器不存放数据,所有数据都保存在客户端,每次请求都发回服务器,用解析token的时间来换取session的储存空间,从而减轻服务器的压力,减少频繁的查询数据库。token 完全由应用管理,所以它可以避开同源策略。

什么是 JWT?

JWT的原理

JWT的原理是,服务器认证以后,生成一个 JSON 对象,发回给用户,以后,用户与服务端通信的时候,都要发回这个 JSON 对象。服务器完全只靠这个对象认定用户身份。为了防止用户篡改数据,服务器在生成这个对象的时候,会加上签名。服务器就不保存任何 session 数据了,也就是说,服务器变成无状态了,从而比较容易实现扩展。 image.png

JWT的数据结构

  • Header(头部)

    Header部分是一个JSON对象,描述JWT的元数据,使用Base64编码转成字符串。

  • Payload(负载)

    Payload是一个JSON对象,用来存放实际需要传递的数据,使用Base64编码转成字符串。

    • iss (issuer):签发人
    • exp (expiration time):过期时间
    • sub (subject):主题
    • aud (audience):受众
    • nbf (Not Before):生效时间
    • iat (Issued At):签发时间
    • jti (JWT ID):编号
  • Signature(签名)

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

JWT的特点

  • 默认不加密,也可以加密
  • 可以用于认证,也可以用于交换信息。降低服务器查询数据库的次数,减小服务器压力
  • 服务器无状态,因此无法在使用过程中废除某个Token,或者更改Token的权限。即一旦JWT签发了,在到期之前始终有效,除非服务器部署额外的逻辑
  • JWT本身包含了认证信息,为保证安全性,有效期应设置得比较短
  • 为了减少盗用,JWT应使用HTTPS协议传输

token存入localstorage还是cookie好

  • 将Token存储于LocalStorage或SessionStorage
    • 由于LocalStorage 和 SessionStorage 都可以被 javascript 访问,所以容易受到XSS攻击。尤其是项目中用到很多第三方的Javascript类库。另外,需要应用程序来保证Token只在HTTPS下传输。
  • 将Token存储于Cookie
    • 优点:可以指定 httpOnly,来防止被Javascript读取,也可以指定secure,来保证token只在HTTPS下传输
    • 缺点:不符合Restful 最佳实践。容易遭受CSRF攻击 (可以在服务器端检查 Refer 和 Origin) 推荐使用Cookie来存储Token:相比较而言,Web Storage比Cookie更容易受到攻击。

可以看这篇:JWT Token存储在Cookie还是LocalStorage

参考文献1:阮一峰老师的《Cookie的SameSite属性》

参考文献2:Cookie、localStorage和sessionStorage的区别?

参考文献3:傻傻分不清之 Cookie、Session、Token、JWT