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

🌌 365bet官方博客 ⏱️ 2025-08-24 21:13:40 👤 admin 👁️ 3123 ⭐ 836
主流的用户身份认证方案?都在这里!

前言

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

用户向服务器发送用户名和密码,以发起登录请求。服务器对用户提供的信息进行验证。验证通过后,在当前会话(session)中保存相关数据,例如用户角色、登录时间等关键信息。服务器向用户返回一个唯一的 session_id,并将其写入用户的 Cookie 中。用户后续的每一次请求,都会通过 Cookie 将 session_id 传递回服务器。服务器接收到 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 ,这样相比放在 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)]

🛸 相关文章

电脑安装打印机方法及虚拟打印机使用指南
365bet官方博客

电脑安装打印机方法及虚拟打印机使用指南

📅 08-05 👁️ 9673
人人贷加盟介绍
365比分

人人贷加盟介绍

📅 07-22 👁️ 3644