Skip to content

前后端鉴权方案

· 51 min

Token、Cookie、Session、JWT、单点登录 是什么?有什么作用?你一般是怎么做的?以及你是怎么存储的呢?那你又是怎么保证 的安全的呢?

image-20260105014205456

0 概念#

tongyi-mermaid-2026-01-06-170626

1. 认证(Authentication)#

“你是谁?” —— 验证用户身份的真实性

实现机制:

凭证类型如何工作存储位置特点
Session + Cookie后端创建 Session(存用户ID),返回 JSESSIONID Cookie浏览器自动管理 Cookie有状态(服务端需存储 Session)
Token(如 JWT)后端签发包含用户信息的加密 Token前端存 localStorage 或 Cookie无状态(Token 自包含信息)

认证成功 = 凭证有效 + 能解析出合法用户身份

⚠️ 注意:Token 本身不是认证,验证 Token 才是认证!

2. 授权(Authorization)#

“你能做什么?” —— 定义用户的角色和权限规则

实现机制:

授权是“静态策略”,发生在系统设计或管理配置阶段

3. 鉴权 / 权限控制(Access Control)#

“这次操作允许吗?” —— 在具体请求时执行权限检查

实现机制(运行时检查):

后端收到带凭证的请求后:

  1. 先认证:解析 Cookie 或 Token → 得到 userId = 1001
  2. 再鉴权:根据授权策略判断是否允许操作

1 HTTP 基本鉴权#

在 HTTP 中,基本认证方案(Basic Access Authentication) 是一种允许客户端(通常是网页浏览器)通过提供用户名和密码来验证身份的简单机制。

由于安全性极低,几乎所有面向公众的线上网站都不会使用该方案,仅用于了解或内部低风险场景。

1.1 认证流程图#

tongyi-mermaid-2026-01-07-012143

1.2 认证步骤解析#

  1. 客户端(如浏览器): 向服务器请求一个受保护的资源,初始请求不包含认证信息。

    GET /list/ HTTP/1.1
    Host: www.baidu.com
  2. 服务器:发现请求未认证,返回 401 Unauthorized 状态码,并在响应头中要求客户端进行 Basic 认证。

    HTTP/1.1 401 Unauthorized
    www-Authenticate: Basic realm= "baidu.com"
    • Basic 表示认证方案;
    • realm=“baidu.com” 定义了安全域,提示用户输入该域的凭据。
  3. 客户端: 浏览器自动弹出登录对话框,用户输入用户名和密码后,客户端将凭据按 用户名:密码 格式进行 Base64 编码(不是加密),并添加到请求头中重新发送。

    GET /list/ HTTP/1.1
    Host: www.baidu.com
    Authorization: Basic aHR0cHdhdGNoOmY= // 示例:对应 "httpwatch:f"
  4. 服务器: 解码 Authorization 头中的 Base64 字符串,验证用户名和密码。若正确,返回请求的资源。

    HTTP/1.1 200 OK
    Content-Type: application/json
    ...

1.3 优缺点#

实现简单,所有主流浏览器和 HTTP 客户端均原生支持。

  1. 极度不安全
    • 凭据仅经 Base64 编码(可轻松解码还原为明文),等同于明文传输
    • 若未使用 HTTPS,任何中间人(如公共 Wi-Fi)都可窃取用户名和密码。
    • 即使使用 HTTPS,凭证无时效性、无法撤销,一旦泄露即可长期冒用。
  2. 无法主动注销
    • 浏览器会缓存 Basic Auth 凭据,直到关闭标签页、窗口或清除浏览器数据
    • 没有标准方法通过代码强制清除该凭据,用户体验差。
  3. 无定制化 UI
    • 登录框由浏览器强制弹出,样式和交互无法自定义,不适合现代 Web 应用。

1.4 使用场景#

内部网络,或者对安全要求不是很高的网络。

Session-Cookie 是一种经典的 Web 认证机制,利用服务端的 Session(会话数据)和客户端的 Cookie(会话标识)协同工作,实现用户身份的持续验证。

⚠️ 注意:Session 数据本身存储在服务端,Cookie 仅存储 Session ID,二者分工明确。

HTTP 是无状态协议,服务器无法天然识别多次请求是否来自同一用户。 Cookie 是服务器通过 Set-Cookie 响应头下发给浏览器的小段数据,浏览器会在后续同域请求中自动携带它,从而实现“状态记忆”。

特点:

2.2 什么是 Session#

Session 的抽象概念是会话,是无状态协议通信过程中,为了实现中断/继续操作,将用户和服务器之间的交互进行的一种抽象;

具体来说,是服务端为每个用户维护的会话状态对象,用于存储登录状态、用户信息、购物车等内容。

特点:

image-20260105014258033

  1. 客户端:发送用户名/密码到 /login 接口;
  2. 服务器
    • 验证凭据;
    • 创建 Session(如 { userId: 1001, role: 'user' }),存入内存/Redis;
    • 生成唯一标识字符串会话身份凭证 session_id(如 abc123);
    • 通过响应头 Set-Cookie: sid=abc123; HttpOnly; Secure 返回;
  3. 客户端:浏览器自动保存 Cookie,后续请求自动携带;
  4. 服务器:每次请求解析 Cookie 中的 sid,查询服务端 Session,验证有效性,恢复用户上下文;
  5. 至此客户端与服务器的通信变成有状态的通信。

2.7 使用场景#

2.8 前端常用的 Session 库推荐#

3 Token 鉴权#

传统 Session-Cookie 机制存在明显短板:服务端需维护会话状态,难以水平扩展;在分布式系统中需引入 Redis 等外部存储,增加架构复杂度。为解决这些问题,基于 Token 的无状态鉴权机制应运而生

3.1 Token(令牌)#

Token 是服务端在用户认证成功后签发的一串唯一凭证字符串。客户端后续请求携带此 Token,服务端仅需验证其有效性即可授权访问资源。

一句话概括:Token 是访问受保护 API 接口所需的资源凭证

早期自定义 Token 的组成:

uid (用户唯一的身份标识) + time (当前时间的时间戳) + sign (基于上述信息 + 密钥生成的哈希签名)

⚠️ 注意:这种“自定义 Token”仍需服务端查库验证用户权限,并非真正的无状态。真正实现无状态的是 JWT(见第 4 节)。

Token 流程图:

tongyi-mermaid-2026-01-07-023512

  1. 客户端: 输入用户名和密码请求登录校验;
  2. 服务器: 收到请求,去验证用户名与密码;验证成功后,服务端会签发一个 Token 并把这个 Token 发送给客户端;
  3. 客户端: 收到 Token 以后需要把它存储起来,web 端一般会放在 localStorage 或 Cookie 中,移动端原生 APP 一般存储在本地缓存中;
  4. 客户端发送请求: 向服务端请求 API 资源的时候,将 Token 通过 HTTP 请求头 Authorization 字段或者其它方式发送给服务端;
  5. 服务器: 收到请求,然后去验证客户端请求里面带着的 Token ,如果验证成功,就向客户端返回请求的数据,否则拒绝返还(401)。

Token 的优点:

Token 的缺点:

3.2 Refresh Token(刷新令牌)#

为平衡安全性与用户体验,采用双 Token 机制:

Token 类型作用有效期存储位置安全要求
Access Token访问业务 API短(如 15 分钟)前端内存/LocalStorage可宽松传输
Refresh Token获取新的 Access Token长(如 7 天)HttpOnly Cookie / 安全存储高(需严格校验)

Token 的客户端存储方式:

方式优点缺点适用场景
HttpOnly Cookie自动携带、防 XSS易受 CSRF 攻击Web 端 SSO(同主域)
LocalStorage避免 CSRF、前端易操作无法跨子域、易受 XSS前后端分离单页应用

SSO 场景必选 Cookie:通过 Domain=.example.com 实现子域共享(如 a.example.comb.example.com)。

Refresh Token 流程图:

image-20260105014328630

  1. 客户端: 输入用户名和密码请求登录校验;
  2. 服务端: 收到请求,验证用户名与密码;验证成功后,服务端会签发一个 Access TokenRefresh Token 并返回给客户端;
  3. 客户端:Access TokenRefresh Token 存储在本地;
  4. 客户端发送请求: 请求数据时,携带 Access Token 传输给服务端;
  5. 服务端:
    • 验证 Access Token 有效:正常返回数据
    • 验证 Access Token 过期:拒绝请求
  6. 客户端 ( Access Token 已过期) 则重新传输 Refresh Token 给服务端;
  7. 服务端 ( Access Token 已过期) 验证 Refresh Token ,验证成功后返回新的 Access Token 给客户端;
  8. 客户端: 重新携带新的 Access Token 请求接口;
维度Session-CookieToken (JWT)
存储位置服务端(内存/Redis)客户端(Cookie/LocalStorage)
状态有状态无状态
扩展性差(需共享 Session)极佳(天然分布式)
安全性易受 CSRF 攻击避免 CSRF(若不用 Cookie)
适用场景同域 Web 应用跨域、移动端、微服务

4 JWT(JSON Web Token)鉴权#

自定义 Token 后续请求仍需查库(Token 映射表),未完全实现无状态。JWT 通过“自包含”设计彻底解决此问题

无论是自定义 Token 还是 JWT,在用户“首次登录”时,服务端都必须查询数据库验证用户名和密码

4.1 什么是 JWT#

JWT(RFC 7519)是一种开放标准,用于在各方之间安全地传输 JSON 声明。其核心思想:将用户信息直接编码进 Token,服务端无需查库

4.2 JWT 的组成#

JWT 由三部分 Base64Url 编码的字符串组成,以 . 分隔:

xxxxx.yyyyy.zzzzz

1、Header(头部)

{
"alg": "HS256", // 签名算法
"typ": "JWT" // Token 类型
}

2、Payload(负载)

包含声明(Claims),分为三类:

⚠️ 重要:Payload 默认不加密(仅 Base64 编码),敏感信息需额外加密!

3、Signature(签名)

base64UrlEncode(header) + "." + base64UrlEncode(payload) 使用密钥签名:

HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
'your-secret-key'
)

作用:确保 Token 未被篡改(服务端用相同密钥验签)。

4.3 JWT 的使用方式#

4.4 JWT 的认证流程图#

其实 JWT 的认证流程与 Token 的认证流程差不多,只是不需要再单独去查询数据库查找用户用户;简要概括如下:

image-20260105014427030

4.5 JWT 的优点#

4.6 JWT 的缺点#

问题原因解决方案
无法主动失效服务端无状态,无法撤销已签发 Token1. 设置短有效期(15-30分钟) 2. 引入 Redis 黑名单(记录失效 Token)
信息更新延迟Payload 是签发时的快照1. 仅存必要字段(如 userID) 2. 敏感操作前二次验证

4.7 前端常用的 JWT 库推荐#

这些中间件自动拦截请求、验证 JWT,并将 payload 挂载到 req.user / ctx.state.user

5 单点登录(Single Sign On)和联合身份(Federated Identity)#

1、单点登录SSO是用户体验目标

一次登录,全网通行:用户只需在身份提供方(IdP)认证一次,即可访问所有相互信任的应用系统(SP),无需重复登录。

2、联合身份是架构模式

联合身份(Federated Identity)是指用户使用一个身份提供商(Identity Provider, IdP),例如微信、Google、企业 AD 等,来登录多个依赖方(Relying Party, RP)或服务提供商(Service Provider, SP)。

典型场景:

核心机制:

跨域的SSO通常就是通过联合身份实现的

5.1 SSO 的典型应用场景#

5.2 SSO 技术选型指南#

场景推荐方案原因
同主域 Web 应用(如 *.baidu.comCookie + Session利用 Cookie Domain 共享,实现简单
跨域系统 / 微服务Cookie + JWT无状态、跨域友好、部署成本低
第三方登录(微信/QQ)OAuth 2.0 + OIDC标准化授权协议,支持用户授权
企业级高安全需求CAS / SAML支持单点登出、多因素认证、审计日志

混合架构(JWT + Redis)#

尽管 JWT 无状态,但企业级 SSO 需支持强制登出实时权限变更,因此常采用混合模式。

原理

流程:

  1. 用户在 SSO 中心登录成功。
  2. 服务端生成 随机 Token(如 UUID)
  3. Token → {userId, roles, ...} 存入 Redis,设置 TTL。
  4. 通过 Set-Cookie 下发 Token(Domain=.company.com)。
  5. 业务系统收到请求后:
    • 携带 Token 查询 Redis
    • 若存在 → 授权;若不存在 → 401

优势

缺点:有状态、需查库,性能略低。

同域下的 SSO(主域名相同)#

当百度网站存在两个相同主域名下的贴吧子系统 tieba.baidu.com 和网盘子系统 pan.baidu.com 时,以下为他们实现 SSO 的步骤:

  1. 客户端: 用户访问某个子系统时(例如 tieba.baidu.com),如果没有登录,则跳转至 SSO 认证中心提供的登录页面进行登录;
  2. 服务端: 登录认证后,服务端把登录用户的信息存储于 Session 中,并且附加在响应头的 Set-Cookie 字段中,设置 Cookie 的 Domain 为 .baidu.com
  3. **客户端:**再次发送请求时,携带主域名 Domain 下的 Cookie 给服务器,此时服务端就可以通过该 Cookie 来验证登录状态了;

跨域下的 SSO(主域名不同)#

当主域名不同,需CAS(Central Authentication Service)中央授权服务

CAS 核心票据:

票据全称作用存储位置
TGTTicket Granting Ticket用户在 CAS 的全局登录凭证CAS 服务端 Session
TGCTicket Granting CookieTGT 的引用(Session ID)浏览器 Cookie (Domain=sso.com)
STService Ticket一次性访问某服务的票据URL 参数传递

单点登录下的 CAS 流程图:

image-20260105014450508

  1. 用户访问 系统 A(如 taobao.com),未登录。
  2. 系统 A 重定向用户到 CAS 认证中心(如 sso.com/login?service=taobao.com)。
  3. 用户在 CAS 登录成功后,CAS:
    • 生成一个 TGT(Ticket Granting Ticket,存服务端)
    • 设置 TGC(Ticket Granting Cookie,存浏览器)
    • 生成一个一次性 ST(Service Ticket,如 ST-12345
  4. CAS 重定向用户回系统 A,URL 带上 ST: https://taobao.com?ticket=ST-12345
  5. 系统 A 拿着 ST 去 CAS 后台验证(通过 HTTPS 请求 /serviceValidate?ticket=ST-12345&service=taobao.com)。
  6. CAS 验证 ST 有效后,返回用户身份信息(如用户名)。
  7. 系统 A 创建自己的会话(如 Session 或 JWT),并让用户登录。

CAS 一般提供四个接口:

CAS 安全增强:

5.3 SSO 的优缺点#

优点:

缺点与风险:

6 OAuth 2.0#

在浏览网站时,我们常看到“使用微信/QQ/微博账号登录”的选项。这种无需向第三方网站提供账号密码即可登录的方式,背后依赖的正是 OAuth 2.0 协议

⚠️ 重要澄清OAuth 2.0 本质是“授权”协议,不是“认证”协议。 它解决的问题是:“是否允许第三方应用代表我访问我的资源?” 而“登录”(即身份认证)通常是基于 OAuth 2.0 扩展的 OpenID Connect(OIDC)实现的。但在实践中,许多平台(如微信、QQ)将授权与认证结合使用,因此用户感知为“第三方登录”。

协议目的返回的关键令牌
OAuth 2.0授权(Authorization)
“是否允许 App 访问我的资源?”
access_token(用于访问 API)
OIDC认证 + 授权
“用户是谁?并允许 App 访问其资源”
id_token(JWT,含用户身份) + access_token

OAuth 2.0 是目前最主流的开放授权标准(RFC 6749),相比 1.0 版本,流程更简洁、安全性更高。

6.1 什么是 OAuth 2.0?#

OAuth 2.0 是一个开放授权框架,允许用户(资源拥有者)授权第三方应用(客户端)访问其在服务提供者(如微信、QQ)上的受保护资源,而无需将用户名和密码透露给第三方

核心角色:

角色说明
Resource Owner(资源拥有者)通常是用户,拥有对资源的控制权
Client(客户端)请求访问用户资源的第三方应用(如 CSDN、掘金)
Authorization Server(授权服务器)验证用户身份并颁发访问令牌(如 open.weixin.qq.com
Resource Server(资源服务器)存储用户数据的服务(如微信用户信息 API)

典型场景: 用户点击“微信登录” → 微信授权服务器弹出确认页 → 用户同意 → 第三方应用获得 Token → 调用微信 API 获取用户昵称/头像。

令牌(Token) vs 密码(Password)

特性令牌(Token)密码(Password)
有效期短期(如 2 小时),自动过期长期有效,除非用户修改
可撤销性可随时由用户或服务端撤销无法单独撤销,需改密
权限范围(Scope)可限制为只读、特定接口等通常拥有账户全部权限
用途仅用于 API 访问用于登录 + 全权限操作

OAuth 2.0 对于如何颁发令牌的细节,规定得非常详细。具体来说,一共分成四种授权模式 (Authorization Grant) ,适用于不同的互联网场景。

6.2 授权码模式#

授权码(Authorization Code Grant) 方式,指的是第三方应用先申请一个授权码,然后再用该码获取令牌并用令牌访问资源。

这是 最安全、最推荐 的 OAuth 2.0 流程,适用于有后端的 Web 应用(如传统网站、前后端分离系统)。

授权码通过前端传送,Access Token 始终在服务端交换,不会暴露给浏览器。

流程图:

tongyi-mermaid-2026-01-07-220723

  1. 客户端:

    打开网站 A,点击登录按钮,请求 A 服务,A 服务重定向 (重定向地址如下) 至授权服务器 (如QQ、微信授权服务)。

    GET https://qq.com/oauth/authorize?
    response_type=code&
    client_id=CLIENT_ID&
    redirect_uri=CALLBACK_URL&
    scope=read

    上面 URL 中,response_type 参数表示要求返回授权码(code),client_id 参数让 B 知道是谁在请求,redirect_uri 参数是 B 接受或拒绝请求后的跳转网址,scope 参数表示要求的授权范围(这里是只读)

  2. 授权服务器:

    授权服务网站 会要求用户登录,然后询问是否同意给予 A 网站授权。用户表示同意,这时授权服务网站 就会跳回 redirect_uri 参数指定的网址。跳转时,会传回一个授权码,就像下面这样。

    HTTP/1.1 302 Found
    Location: https://a.com/callback?code=AUTHORIZATION_CODE

    上面 URL 中,code 参数就是授权码。

  3. 网站 A 服务器:

    拿到授权码以后,就可以向 授权服务器 (qq.com) 请求令牌,请求地址如下:

    POST /oauth/token HTTP/1.1
    Host: qq.com
    Content-Type: application/x-www-form-urlencoded
    grant_type=authorization_code&
    code=AUTHORIZATION_CODE&
    redirect_uri=https%3A%2F%2Fa.com%2Fcallback&
    client_id=CLIENT_ID&
    client_secret=CLIENT_SECRET

    🔒 更安全的做法(RFC 推荐): 将 client_idclient_secret 放在 HTTP Basic Auth 头中,而不是 body:

    POST /oauth/token HTTP/1.1
    Host: qq.com
    Authorization: Basic base64encode("CLIENT_ID:CLIENT_SECRET")
    Content-Type: application/x-www-form-urlencoded
    grant_type=authorization_code&
    code=AUTHORIZATION_CODE&
    redirect_uri=https%3A%2F%2Fa.com%2Fcallback

    上面 URL 中,client_id 参数和 client_secret 参数用来让授权服务器确认 A 的身份(client_secret 参数是保密的,因此只能在后端发请求),grant_type 参数的值是 AUTHORIZATION_CODE,表示采用的授权方式是授权码,code 参数是上一步拿到的授权码,redirect_uri 参数仅用于验证(必须与Step1一致),不用于跳转

    image-20260105014531797
  4. 授权服务器:

    收到请求以后,验证通过,就会颁发令牌。具体做法是直接在 HTTP 响应体中返回 JSON不涉及任何重定向

    HTTP/1.1 200 OK
    Content-Type: application/json
    Cache-Control: no-store
    Pragma: no-cache
    {
    "access_token": "ACCESS_TOKEN",
    "token_type": "bearer",
    "expires_in": 2592000,
    "refresh_token": "REFRESH_TOKEN",
    "scope": "read",
    "uid": "100101"
    }

    上面 JSON 数据中,access_token 字段就是令牌,A 网站在后端拿到。

场景正确做法
调用 /token 获取令牌必须用 POST,参数放在 请求体,Content-Type: application/x-www-form-urlencoded
调用 /authorize 获取授权码GET,参数放在 URL 查询字符串(因为要重定向浏览器)

🔒 安全增强:PKCE(RFC 7636) 对于无后端的 SPA 应用(如纯 React/Vue),即使使用授权码模式,也必须配合 PKCE(Proof Key for Code Exchange)防止授权码拦截攻击。此时不再依赖 client_secret

6.3 密码模式(Resource Owner Password Credentials Grant)#

如果你高度信任某个应用,OAuth 2.0 也允许用户直接向第三方应用提供账号和密码,由应用代为申请 Token。

步骤详解:

  1. 客户端:

    A 网站要求用户提供 授权服务器(qq.com) 的用户名和密码。拿到以后,A 就直接向 授权服务器 请求令牌。

    POST /token HTTP/1.1
    Host: oauth.b.com
    Content-Type: application/x-www-form-urlencoded
    grant_type=password&
    username=user@example.com&
    password=secret&
    client_id=CLIENT_ID&
    client_secret=CLIENT_SECRET <!-- 如果需要 -->

    上面 URL 中,grant_type 参数是授权方式,这里的 password 表示”密码式”,usernamepassword授权服务器 的用户名和密码。

  2. 授权服务器:

    授权服务器 验证身份通过后,直接给出令牌。

    注意,这时不需要跳转,而是把令牌放在 JSON 数据里面,作为 HTTP 回应,A 网站因此拿到令牌。

适用场景(极其有限):

6.4 客户端凭证模式(Client Credentials Grant)#

客户端模式指客户端以自己的名义,而不是以用户的名义,向 授权服务器 请求 Token,用于访问与用户无关的 API

步骤详解:

  1. 客户端:向授权服务器进行身份认证,并要求一个访问令牌。

    POST /token
    Content-Type: application/x-www-form-urlencoded
    grant_type=client_credentials&
    client_id=CLIENT_ID&
    client_secret=CLIENT_SECRET

    上面 URL 中,grant_type 参数等于 client_credentials 表示采用凭证式,client_idclient_secret 用来让 授权服务器 确认 A 的身份。

  2. 授权服务器:验证通过以后,直接返回令牌。

典型场景:

6.5 总结#

上述主要比较浅显的讲解了 OAuth2.0 的基本逻辑,如若想详细深入的了解,可查看官方文档 OAuthRFC 6749; 亦可查看 OAuth 2.0 概念及授权流程梳理 做对比

7 唯一登录(Single Active Session)#

假设现在产品经理提一个需求:我想要实现用户只能在一个设备上登录,禁止用户重复登录

7.1 什么是唯一登录#

唯一登录是指系统强制同一账号在同一时间只能有一个活跃会话。当用户在新设备/浏览器登录时,旧会话立即失效。

唯一登录是业务层会话控制策略,与底层认证协议如OAuth 2.0无关。

✅ 典型需求:

❌ 常见误解:

7.2 唯一登录流程图#

image-20260105014644041

Token 本身可以自带有效期(如 JWT 的 exp 声明),但仅靠 Token 自身无法实现“主动失效”或“会话粒度控制”——这时就需要会话表(Session Table)来配合管理。

  1. 会话表结构

    CREATE TABLE user_sessions (
    id BIGINT PRIMARY KEY,
    user_id VARCHAR(64) NOT NULL,
    token VARCHAR(255) NOT NULL, -- JWT 或随机字符串
    device_info JSON, -- 可选:记录设备/IP
    active BOOLEAN DEFAULT true,
    created_at TIMESTAMP,
    expires_at TIMESTAMP
    );
  2. 登录时

    • 先将该用户所有 active = true 的会话置为 false
    • 再插入新会话。
  3. 每次 API 请求

    • 验证 Token 是否存在且 active = true
    • 若否,返回 401 并提示“账号已在其他设备登录”。

注意事项:

8 扫码登录#

8.1 什么是扫码登录#

扫码登录通常见于移动端 APP 中,很多 PC 端的网站都提供了扫码登录的功能,无需在网页上输入任何账号和密码,只需要让移动端 APP (如微信、淘宝、QQ等等) 中已登录用户主动扫描 二维码 ,再确认登录,以使 PC 端的同款应用得以快速登录的方式就是 扫码登录

8.2 什么是二维码#

二维码 又称二维条码,常见的二维码为 QR Code,QR 全称 Quick Response,是一个近几年来移动设备上超流行的一种编码方式,它比传统的Bar Code条形码能存更多的信息,也能表示更多的数据类型。

通过上面所述,我们不难发现,扫码登录需要三端 (PC端手机端服务端) 来进行配合才能达到登录成功的效果;

8.3 扫码登录的认证流程图#

image-20260105014738762

8.4 扫码登录的步骤详解 (待扫码阶段、待确认阶段、已确认阶段)#

待扫码阶段:

  1. PC端:

    打开某个网站 (如taobao.com) 或者某个 APP (如微信) 的扫码登录入口;就会携带 PC 端的设备信息向服务端发送一个获取二维码的请求;

  2. 服务端:

    服务器收到请求后,随机生成一个 UUID 作为二维码 ID,并将 UUID 与 PC 端的设备信息 关联起来存储在 Redis 服务器中,然后返回给 PC 端;同时设置一个过期时间,在过期后,用户登录二维码需要进行刷新重新获取。

  3. PC 端:

    收到二维码 ID 之后,将二维码 ID 以 二维码的形式 展示,等待移动端扫码。并且此时的 PC 端开始轮询查询二维码状态,直到登录成功。

    如果移动端未扫描,那么一段时间后二维码会自动失效。

已扫码待确认阶段:

  1. 手机端:

    打开手机端对应已登录的 APP (微信或淘宝等),开始扫描识别 PC 端展示的二维码;

    移动端扫描二维码后,会自动获取到二维码 ID,并将移动端登录的信息凭证(Token)和二维码 ID 作为参数发送给服务端,此时手机必须是已登录(使用扫描登录的前提是移动端的应用为已登录状态,这样才可以共享登录态)。

  2. 服务端:

    收到手机端发来的请求后,会将 Token 与二维码 ID 关联,为什么需要关联呢?因为,当我们在使用微信时,移动端退出时,PC 端也应该随之退出登录,这个关联就起到这个作用。然后会生成一个临时 Token,这个 Token 会返回给移动端,一次性 Token 用作确认时的凭证。

已确认阶段:

  1. 手机端:

    收到确认信息后,点击确认按钮,移动端携带上一步中获取的 临时 Token 发送给服务端校验;

  2. 服务端:

    服务端校验完成后,会更新二维码状态,并且给 PC 端生成一个 正式的 Token,后续 PC 端就是持有这个 Token 访问服务端。

  3. PC端:

    轮询到二维码状态为已登录状态,并且会获取到了生成的 Token,完成登录,后续访问都基于 Token 完成。

9 一键登录(适用于原生APP)#

9.1 账号密码登录#

大家都知道,最传统的登录方式就是使用账号加密码登录,简单粗暴,一般也不会出现什么问题;

缺点:

  1. 但这种方式要求用户要记住自己的账号和密码,也就是有一个记忆成本。用户为了降低记忆成本,很可能会在不同平台使用同一套账号密码。从安全角度考虑,一旦某个平台的账号密码泄露了,会连累到该用户使用的其他平台。
  2. 另外,由于账号和个人身份无关,意味着同一个用户可以注册多个不同的账号,也就是可能会有恶意注册的情况发生。

直到手机卡的强制实名制才得以解决!

9.2 手机号验证码登录#

随着无线互联的发展以及手机卡实名制的推广,手机号俨然已成为特别的身份证明,与账号密码相比,手机号可以更好地验证用户的身份,防止恶意注册。

但是手机号注册还是需要一系列繁琐的操作:输入手机号、等待短信验证码、输入验证码、点击登录。整个流程少说二十秒,而且如果收不到短信,也就登录补了,这类问题有可能导致潜在的用户流失。

从安全角度考虑,还存在验证码泄漏的风险。如果有人知道了你的手机号,并且窃取到了验证码,那他也能登录你的账号了。

所以就有了一键登录操作!

9.3 什么是一键登录#

我们想一下,为什么我们需要验证码?验证码的作用就是确定这个手机号是你的,那除了使用短信,是否还有别的方式对手机号进行认证?

于是,就有了咱们的主角一键登录。

短信验证码的作用就是证明当前操作页面的用户与输入手机号的用户为相同的人,那么实际上只要我们能够获取到当前手机使用的手机卡号,直接使用这个号码进行登录,不需要额外的操作,这就是一键登录

一键登录能不能做,取决于运营商是否开放相关服务;随着运营商开放了相关的服务,我们现在已经能够接入运营商提供的 SDK 并付费使用相关的服务。

一键登录流程图:

image-20260105014756850

一键登录步骤详解:

  1. SDK 初始化: 调用 SDK 方法,传入平台配置的 AppKey 和 AppSecret
  2. 唤起授权页: 调用 SDK 唤起授权接口,SDK 会先向运营商发起获取手机号掩码的请求,请求成功后跳到授权页。授权页会显示手机号掩码以及运营商协议给用户确认。
  3. 同意授权并登录: 用户同意相关协议,点击授权页面的登录按钮,SDK 会请求本次取号的 Token,请求成功后将 Token 返回给客户端
  4. 取号: 将获取到的 Token 发送到自己的服务器,由服务端携带 Token 调用运营商一键登录的接口,调用成功就返回手机号码。服务端用手机号进行登录或注册操作,返回操作结果给客户端,完成一键登录。

三大运营商开放平台:

注意:

在认证过程中,需要用户打开蜂窝网络,如果手机设备没有插入 SIM 卡、或者关闭蜂窝网络的情况下,是无法完成认证的。所以就算接入一键登录,还是要兼容传统的登录方式,允许用户在失败的情况下,仍能正常完成登录流程。

总结#

类别术语说明
认证/授权协议(标准)OAuth 2.0、OIDC、SAML、CAS定义客户端、用户、服务之间如何安全交换身份和权限信息
会话管理机制(实现)Cookie、Session、Token、JWT用于在认证后维持用户状态的技术手段
身份架构模式(设计范式)联合身份(Federated Identity)、单点登录(SSO)高层业务目标或系统集成模式