主流的用户身份认证方案?都在这里!

前言

在现在的互联网服务中,用户认证是至关重要的环节。其一般流程大致如下:

  1. 用户向服务器发送用户名和密码,以发起登录请求。
  2. 服务器对用户提供的信息进行验证。验证通过后,在当前会话(session)中保存相关数据,例如用户角色、登录时间等关键信息。
  3. 服务器向用户返回一个唯一的 session_id,并将其写入用户的 Cookie 中。
  4. 用户后续的每一次请求,都会通过 Cookie 将 session_id 传递回服务器。
  5. 服务器接收到 session_id 后,查找前期保存的数据,从而确定用户的身份,进而为用户提供相应的服务和权限。

然而,这种传统的认证模式在扩展性方面存在一定的局限性。在单机环境下,它运行良好,但一旦涉及服务器集群或跨域的服务导向架构,就需要解决 session 数据共享的问题,确保每台服务器都能够读取和使用 session 数据。

例如,假设 A 网站和 B 网站属于同一家公司的关联服务,我们期望用户在其中一个网站成功登录后,访问另一个网站时能够自动登录。那么,如何实现这一功能呢?

方案一:Session 数据持久化

一种可行的解决方案是将 session 数据持久化,例如将其写入数据库或其他持久存储层。这样,各种服务在收到请求后,都可以向持久层请求所需的数据。此方案的优点在于架构清晰,逻辑明确。但缺点也较为明显,其工程量相对较大。而且,如果持久层出现故障,将会导致单点失败,整个系统的稳定性将受到严重影响。

方案二:基于客户端存储的 JWT 方案

另一种创新的方案是服务器不再保存 session 数据,而是将所有与用户相关的数据都保存在客户端。每次请求时,客户端将这些数据发回服务器。JWT(JSON Web Token)就是这种方案的典型代表。

HTTP 的无状态特性

我们都清楚,HTTP 是一种无状态(stateless)的协议。这意味着 HTTP 对于事务处理没有记忆能力,不会保存请求和响应之间的通信状态。每次有新的请求发送时,都会产生相应的新响应。协议本身并不保留之前的请求或响应报文的任何信息。这种设计的初衷是为了能够快速处理大量事务,确保协议的可伸缩性,从而使 HTTP 协议保持简洁高效。

然而,随着 Web 应用的不断发展,这种无状态的特性在某些场景下带来了诸多不便。以用户登录新浪微博为例,用户在登录页输入用户名、密码后进入首页。但由于 HTTP 无状态的特性,HTTP 无法知晓上一次的请求是否通过了验证,更无法获取当前用户的具体信息。

最直接的解决办法或许是在所有的请求中都附带用户名和密码。这种方法虽然在技术上可行,但会极大地增加服务器的负担(因为服务器需要针对每个请求都到数据库进行验证),同时也会给用户带来极差的体验,因为用户需要在每进入一个页面时都输入密码。

为了解决这些问题,各种身份认证机制应运而生,其中较为常见的有 Cookie-Session 机制和 JWT 机制。

Cookie-Session 机制

Cookie 简介

Cookie 是由 HTTP 服务器设置,并保存在浏览器中的小型文本文件,其内容以一系列的键值对形式呈现。在 Chrome 浏览器中,您可以通过开发者工具 -> Application -> Cookies 查看 Cookie 的详细信息。

以下简单介绍一些常见的 Cookie 字段含义:

  • Expires:指定 Cookie 的过期时间。默认情况下,Cookie 在用户关闭浏览器时过期。
  • HttpOnly:此属性指示浏览器不要在除了 HTTP(或者 HTTPS)请求之外暴露 Cookie。通过 JavaScript 脚本无法访问到具有 HttpOnly 属性的 Cookie,这能有效防止 XSS(跨站脚本攻击)。
  • Secure:当设置 Cookie 的 Secure 属性为 true 时,意味着 Cookie 仅能在安全/加密连接(如 HTTPS)下使用。也就是说,只有在 HTTPS 协议下,Cookie 才能被上传到服务器,而在 HTTP 协议下无法上传。

Cookie 的传递过程

  • 浏览器向某个 URL 发送请求。
  • 对应的服务器收到该 HTTP 请求后,生成要发送给浏览器的 HTTP 响应。
  • 在响应头中添加 Set-Cookie 字段,其值为要设置的 Cookie 内容。
  • 浏览器收到来自服务器的 HTTP 响应。
  • 浏览器在响应头中发现了 Set-Cookie 字段,便会将该字段的值保存在内存或硬盘中。
  • 当下一次向该服务器发送 HTTP 请求时,会将服务器设置的 Cookie 附加在 HTTP 请求的 Cookie 字段中。
  • 服务器收到这个 HTTP 请求后,若发现请求头中有 Cookie 字段,就知道已经处理过这个用户的请求了。
  • 过期的 Cookie 会被浏览器自动删除。

Session 介绍

与存储在浏览器中的 Cookie 不同,Session 数据是存储在服务器端的,这样可以避免在客户端存储敏感信息。而且,Session 的存取方式更为灵活,能够存储任何类型的数据,而 Cookie 只能保存 ASCII 字符串,如果需要存取 Unicode 字符或二进制数据,则需要先进行编码。通常,Session 会与 Cookie 配合使用,这就是接下来要探讨的 Cookie-Session 机制。

Cookie-Session 身份验证机制的工作流程

  • 用户输入登录信息。
  • 服务端验证登录信息的正确性。如果验证通过,就在服务器端为该用户创建一个 Session,并将 Session 数据存入数据库。
  • 服务器端向客户端返回带有 sessionID 的 Cookie。
  • 客户端接收到服务器端发来的请求后,在响应头中看到 Set-Cookie 字段,将 Cookie 保存起来。
  • 在接下来的请求中,客户端都会带上这个 Cookie。服务器将收到的 sessionID 与数据库中的进行匹配,如果匹配有效,则处理该请求。
  • 如果用户登出,Session 会在客户端和服务器端都被销毁。

Cookie-Session 机制的缺陷

  • 扩展性不佳:在多服务器的环境下,如何共享 Session 数据成为难题。例如,当用户首次访问的是服务器 A,而第二次请求被转发到服务器 B 时,服务器 B 无法获取用户的状态信息。
  • 安全性欠佳:攻击者可能利用本地 Cookie 进行欺骗和 CSRF(跨站请求伪造)攻击。
  • 对服务器性能有影响:由于 Session 数据保存在服务器端,如果短时间内有大量用户登录,会占用大量服务器内存,影响服务器性能。
  • 跨域问题:Cookie 受到同源策略的限制。

JWT 机制

JWT 的组成

JWT 由三个部分组成:header(头部)、payload(负载)和 signature(签名),每个部分之间使用 . 分隔。其中,header 和 payload 使用 Base64URL 进行编码:

base64UrlEncode(header).base64UrlEncode(payload).signature

Header(头部)

header 部分是一个 JSON 对象,用于描述 JWT 的元数据,例如:

{
  "typ": "JWT",
  "alg": "HS256"
}

其中,typ 表示这是一个 JWT 对象,alg 表示用于创建签名的 Hash 算法,这里使用的是 HMAC-SHA256 算法。

Payload(负载)

payload 部分同样是一个 JSON 对象,实际需要传递的数据就存放在这里。除了使用官方提供的七个字段之外,还可以自定义私有字段,例如:

{
  "sub": "title",
  "name": "Yeoman"
}

需要注意的是,JWT 默认是不加密的,任何人都可以读取其中的内容,因此不要在 payload 中存放敏感信息。

Signature(签名)

signature 是对前两个部分的签名,用于防止数据被篡改。其生成过程如下:

data = base64urlEncode( header ) + "." + base64urlEncode( payload );
signature = Hash( data, secret );

首先,将使用 Base64URL 编码的 header 和 payload 用 . 连接起来,然后使用 header 中指定的 Hash 算法(如上述的 HMAC-SHA256),结合一个密钥对这个字符串进行 Hash 运算,得到 signature。

JWT 的工作流程

  • 前端将自己的用户名和密码发送到后端的接口。
  • 后端核对用户名和密码。如果正确,将用户的一些信息作为 payload,生成 JWT。
  • 后端将 JWT 作为登录成功的返回结果返回给前端。前端可以将其结果保存在 localStorage 或 sessionStorage 中,登出时删除 JWT 即可。(建议不要保存在 Cookie 中,因为使用 Cookie 无法设置 HttpOnly 属性,且存在跨域问题。)
  • 每一次请求都将 JWT 放在 HTTP 请求头中的 Authorization 字段中,格式为 Authorization: Bearer <token>,这样相比放在 Cookie 中能够实现跨域请求。
  • 服务器接收到请求后,对 JWT 进行解码。如果 token 有效,则处理该请求。
  • 用户登出时,在客户端删除 token 即可,与服务端无关。

JWT 的特点

  • JWT 默认是不加密的,因此其安全性相对较低。
  • JWT 的主要目的是验证来源的可靠性,而不是保护数据或防止未经授权的访问。可以将其类比为一张电影票,它只能验证电影票的真伪以及包含一些基本信息,但他人也可能使用您的电影票。一旦 JWT 被暴露,任何人都可能获得相应的权限。为了降低被盗用的风险,JWT 的有效期应设置得相对较短。对于一些重要的权限,使用时应再次对用户进行认证。
  • JWT 最大的缺点是 token 过期处理问题。由于服务器不保存 Session 状态,因此无法在使用过程中废止或更改权限。也就是说,一旦 JWT 签发,在到期之前它始终有效,除非服务器部署额外的逻辑来处理。

几个case

同源策略限制的内容

同源策略限制的内容包括:Cookie、LocalStorage、SessionStorage、IndexedDB 等存储性内容;DOM 节点;Ajax 发送请求后,结果被浏览器拦截。

Cookie 和 Session 的区别

  • 存取方式:Cookie 只能保存 ASCII 字符串,如需存取 Unicode 字符或二进制数据,需先进行编码。Session 则可以存取任何类型的数据。
  • 隐私策略:Cookie 存储在浏览器中,Session 存储在服务器上。
  • 服务器压力:Session 保存在服务器上,每个用户都会产生一个 Session。在并发访问用户众多的情况下,会产生大量的 Session,消耗大量服务器内存。

分布式情况下的 Session 和 Token

我们已经了解到 Session 是有状态的,通常存储于服务器的内存或硬盘中。当服务器采用分布式或集群架构时,Session 就会面临负载均衡的问题。

在大型互联网公司中,为了支撑巨大的流量,后端往往需要多台服务器共同来处理前端用户的请求。如果用户在 A 服务器登录,第二次请求却被分发到服务 B,就可能出现登录失效的问题。

针对分布式 Session,一般有以下几种解决方案:

  • Nginx 的 ip_hash 策略:服务端使用 Nginx 作为代理,每个请求按照访问 IP 的哈希值进行分配。这样,来自同一 IP 的请求会固定访问一个后台服务器,避免了在服务器 A 创建 Session,第二次请求却分发到服务器 B 的情况。
  • Session 复制:任何一个服务器上的 Session 发生变更(如增加、删除、修改),该节点会将这个 Session 的所有内容序列化,然后广播给其他所有节点。
  • 共享 Session:将服务端设置为无状态,使用缓存中间件来统一管理用户的 Session 等信息,确保分发到每一个服务器的响应结果都一致。

综合考虑,建议采用第三种方案。

而 Token 是无状态的,Token 字符串中保存了所有的用户信息。客户端登录时向服务端传递信息,服务端接收后将用户信息加密生成 Token 并返回给客户端。客户端将 Token 存放在 localStorage 等容器中。客户端每次访问时都传递 Token,服务端对 Token 进行解密,从而确定用户身份。通过这种 CPU 加解密的方式,服务端无需存储 Session,节省了存储空间,有效地解决了负载均衡和多服务器环境下的问题。这种方法也就是 [JWT(Json Web Token)]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/765867.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

算法训练营day24--93.复原IP地址 +78.子集 +90.子集II

一、93.复原IP地址 题目链接&#xff1a;https://leetcode.cn/problems/restore-ip-addresses/ 文章讲解&#xff1a;https://programmercarl.com/0093.%E5%A4%8D%E5%8E%9FIP%E5%9C%B0%E5%9D%80.html 视频讲解&#xff1a;https://www.bilibili.com/video/BV1fA4y1o715 1.1 初…

MyBatis入门案例

实施前的准备工作&#xff1a; 1.准备数据库表2.创建一个新的springboot工程&#xff0c;选择引入对应的起步依赖&#xff08;mybatis、mysql驱动、lombok&#xff09;3.在application.properties文件中引入数据库连接信息4.创建对应的实体类Emp&#xff08;实体类属性采用驼峰…

终身免费的Navicat数据库,不需要破解,官方支持

终身免费的Navicat数据库&#xff0c;不需要破解&#xff0c;官方支持 卸载了Navicat&#xff0c;很不爽上干货&#xff0c;Navicat免费版下载地址 卸载了Navicat&#xff0c;很不爽 公司不让用那些破解的数据库软件&#xff0c;之前一直使用Navicat。换了几款其他的数据库试了…

WebStorm 2024 for Mac JavaScript前端开发工具

Mac分享吧 文章目录 效果一、下载软件二、开始安装1、双击运行软件&#xff08;适合自己的M芯片版或Intel芯片版&#xff09;&#xff0c;将其从左侧拖入右侧文件夹中&#xff0c;等待安装完毕2、应用程序显示软件图标&#xff0c;表示安装成功3、打开访达&#xff0c;点击【文…

web权限到系统权限 内网学习第一天 权限提升 使用手工还是cs???msf可以不??

现在开始学习内网的相关的知识了&#xff0c;我们在拿下web权限过后&#xff0c;我们要看自己拿下的是什么权限&#xff0c;可能是普通的用户权限&#xff0c;这个连添加用户都不可以&#xff0c;这个时候我们就要进行权限提升操作了。 权限提升这点与我们后门进行内网渗透是乘…

代码查重软件-自力更生

为了减轻工作量&#xff0c;自研了简单实用的代码查重工具&#xff0c;可以对若干文件之间进行查重。通过调试&#xff0c;相似度大于80%的没有一个是冤枉的。好用。去掉雷同的&#xff0c;其他的代码再慢慢看。

pads layout 脚本导出不能运行excle解决办法

在一台新的电脑上安装好PADS&#xff0c;打开PCB文件导出坐标文件时&#xff1a; 出现“ActiveX Automation: server could not be found.”的问题,导致无法成功导出文件,错误提示截图如下&#xff1a; 导致上述问题的原因是在我们配置导出带坐标的脚本时,默认使用的是微软…

服务器连接不上

记录今天2024/07/02的问题&#xff1a; 我今天真的是非常无语&#xff0c;今天在连服务器的时候&#xff0c;突然发现连不上了。 后来才意识到&#xff0c;原来是我笔记本先是开了全局代理&#xff0c;然后再用easy connected连接。当时还跳出了一个窗口如下&#xff0c;我当时…

2024 MWC上海:创新力量驱动未来先行,移远智慧点亮数字蓝海

6月26日&#xff0c;2024年世界移动通信大会&#xff08;MWC上海&#xff09;如期举行&#xff0c;今年的展会以“未来先行”为主题&#xff0c;涵盖“超越 5G、数智制造和人工智能经济”三大技术主题。移远通信作为全球物联网行业的引领者之一&#xff0c;今年不仅在展示内容上…

性能调优 性能监控

1.影响性能考虑点包括&#xff1a; 数据库、应用程序、中间件(tomcat、nginx)、网络和操作系统等方面。 首先考虑自己的应用属于 CPU密集型 还是 IO密集型 cpu密集型 计算&#xff0c;排序&#xff0c;分组查询&#xff0c;各种算法 IO密集型 网络传输&#xff0c;磁盘读…

将数据切分成N份,采用NCCL异步通信,让all_gather+matmul尽量Overlap

将数据切分成N份,采用NCCL异步通信,让all_gathermatmul尽量Overlap 一.测试数据二.测试环境三.普通实现四.分块实现 本文演示了如何将数据切分成N份,采用NCCL异步通信,让all_gathermatmul尽量Overlap 一.测试数据 1.测试规模:8192*8192 world_size22.单算子:all_gather:0.035…

JDBC链接kerberos认证的impala数据库报错问题解决

先上代码 public static Connection connectToImpala() {try {log.info("ketTabPath:" ketTabPath);log.info("krb5Path:" krb5Path);System.setProperty("java.security.krb5.conf", krb5Path);System.setProperty("sun.security.krb5.…

冒泡排序、选择排序、菱形

冒泡排序、选择排序、菱形 文章目录 一、冒泡排序二、选择排序三、菱形 一、冒泡排序 思路&#xff1a; 外层&#xff08;第一层&#xff09;循环控制循环次数&#xff0c;和业务无关 内层&#xff08;第二层&#xff09;循环用于比较相邻的2个值的大小&#xff0c;根据小到大…

用MySQL+node+vue做一个学生信息管理系统(五):学生信息增删改的实现

先实现增加信息&#xff1a; post参数的获取&#xff1a;express中接受post请求参数需要借助第三方包 body-parser 下载npm install body-parser //引入body-parser模块 const bodyParser require(body-parser); //拦截所有请求,配置body-parser模块 //extended:false 方法…

TransMIL:基于Transformer的多实例学习

MIL是弱监督分类问题的有力工具。然而&#xff0c;目前的MIL方法通常基于iid假设&#xff0c;忽略了不同实例之间的相关性。为了解决这个问题&#xff0c;作者提出了一个新的框架&#xff0c;称为相关性MIL&#xff0c;并提供了收敛性的证明。基于此框架&#xff0c;还设计了一…

昇思MindSpore学习总结六——函数式自动微分

神经网络的训练主要使用反向传播算法&#xff0c;模型预测值&#xff08;logits&#xff09;与正确标签&#xff08;label&#xff09;送入损失函数&#xff08;loss function&#xff09;获得loss&#xff0c;然后进行反向传播计算&#xff0c;求得梯度&#xff08;gradients&…

怎么使用MarkDown画矩阵

本文首发于公众号“AntDream”&#xff0c;欢迎微信搜索“AntDream”或扫描文章底部二维码关注&#xff0c;和我一起每天进步一点点 今天写文章需要用到矩阵&#xff0c;记录一下 画矩阵需要用到特殊的语法 &#xff08;1&#xff09;画普通矩阵&#xff0c;不带括号的 $$be…

SHA1算法

什么是SHA1算法&#xff08;Secure Hash Algorithm&#xff09; SHA1算法也是一种哈希算法&#xff0c;也称单向散列算法&#xff0c;不可逆&#xff0c;适用于数字签名标准。与MD5大同小异。 算法流程 &#xff08;1&#xff09;明文处理&#xff0c;对明文进行填充&#x…

一文揭秘:CRM如何助力家居建材企业可持续发展?

01、家居建材行业业务高速发展&#xff0c;对数字化转型提出越来越高诉求 家居建材行业是国民经济的重要基础产业&#xff0c;是改善人居条件、治理生态环境和发展循环经济的重要支撑。家居建材是土木工程和建筑工程中使用材料的统称&#xff0c;包括天花板、瓷砖、门、窗、锁…

【Rust基础入门】Hello Cargo

文章目录 前言Cargo是什么&#xff1f;Cargo的作用查看cargo版本使用cargo创建项目Cargo.toml文件cargo build命令cargo runcargo check为发布构建 总结 前言 在Rust编程中&#xff0c;Cargo扮演着至关重要的角色。它是Rust的包管理器&#xff0c;负责处理许多任务&#xff0c…