前端认证授权方案详解:从基础到实战

作者:后端茶话

时间:2026-10-27

浏览:543

本文从前端视角系统梳理了常见的认证授权方案。详细解析了HTTP Basic认证、Session-Cookie模式、Token及JWT的工作流程与优缺点,并深入探讨了OAuth 2.0标准下的第三方登录实现。结合Node.js代码示例,帮助开发者理解不同场景下的最佳实践与安全考量。

文章目录

概念介绍

在业界,认证与授权已有诸多成熟方案。然而对于前端开发而言,大多数场景下仅需调用服务端提供的登录接口完成身份验证,随后在后续请求中携带对应的 Token 即可。许多公司还会开发 JS SDK,以便各业务项目快速接入认证授权体系,这导致我们往往容易忽略认证授权的底层细节流程。

本文将立足于前端开发视角,介绍业界常见的认证授权方案,并提供简易的实践代码以辅助理解整体流程。

认证

认证(Identification)的核心在于验证当前用户的身份合法性。

常见的认证技术包括以下几种:

  • 身份证
  • 用户名和密码
  • 用户手机:手机短信、手机二维码扫描、手势密码
  • 用户的电子邮箱
  • 用户的生物学特征:指纹、语音、眼睛虹膜

授权

授权(Authorization)是指赋予用户访问系统的权限。在成功认证用户身份后,系统会根据策略授予该用户部分或全部权限。若系统未设置复杂的权限控制需求,通常认证通过后用户即拥有全部权限。

实现授权的方式主要有:

  • cookie
  • session
  • token
  • OAuth

鉴权

鉴权(Authentication)是指系统对用户身份和权限进行鉴定。例如,系统需要校验 session、cookie 或 token 的合法性与有效性,以确认请求是否被允许。

认证、授权和鉴权关系

这三个概念之间存在清晰的前后逻辑关系:认证 => 授权 => 鉴权。例如,当我们登录某个系统时,完成了身份认证和权限授予;在后续使用系统功能时,系统则执行鉴权操作以验证请求的合法性。

在了解相关基础概念后,接下来将详细介绍常见的认证授权方案。

认证授权方案

HTTP 基本认证

基本认证(Basic 认证)是 HTTP/1.0 标准中定义的认证方式,主要通过用户提供用户名和密码来验证用户身份。

基本认证流程图

概念介绍

以下是基本认证的步骤解析:

  • 浏览器向服务器请求受保护的资源。
  • 服务器返回 401 状态码,同时在响应头中携带 WWW-Authenticate: Basic realm=protected_docs。其中 realm 代表资源的安全域,意味着不同权限的资源可能被划分到不同的安全域中。
  • 浏览器弹出窗口请求用户输入账号和密码。用户输入后,浏览器将账号密码进行 Base64 编码,再次发起请求,并在请求头中携带 Authorization: Basic Base64(账号:密码)。
  • 服务器对账号密码进行认证。若认证成功,则返回对应资源;若失败,则返回 403 forbidden。

node 的简单实现

const express = require('express')
const app = express()
const protectedPath = '/protected_docs'
const realms = {
  [protectedPath]: {
    users: ['root'],
  },
}
app.get(protectedPath, (req, res, next) => {
  const realm = realms[req.path]
  const authorization = req.get('authorization')
  if (!authorization) {
    // 告知用户需要身份认证
    res.statusCode = 401
    res.set('WWW-Authenticate', 'Basic realm=' + encodeURIComponent(realm))
    res.end()
    return
  }
  const usernamePasswd = authorization.split(' ')[1] // Basic Y2h5aW5ncDoxMjM0NTY
  const [usrname, passwd] = Buffer.from(usernamePasswd, 'base64')
    .toString()
    .split(':')
  if (!realm.users.includes(usrname)) {
    // 用户不在realm里
    res.statusCode = 401
    res.set('WWW-Authenticate', 'Basic realm=' + encodeURIComponent(realm))
    res.end()
    return
  }
  const isValid = usrname === 'root' && passwd === '123456'
  if (!isValid) {
    // 用户账号、密码验证不通过
    res.statusCode = 403
    res.end()
    return
  }
  res.end(`welecom ${usrname}`)
})
app.listen(3000)

小结

优点:

  • 实现简单,基本所有浏览器都支持。

缺点:

  • 安全性较低,密码在 HTTP 明文传输中仅经过 Base64 编码,容易被解码。
  • 无法主动注销,除非关闭标签页或浏览器,或用户清除历史记录,否则认证信息将一直存在。

使用场景:

  • 适用于内部网络或对安全要求不高的网络环境,例如公司内网 Wiki。

这里补充说明,针对基本认证的缺点,HTTP 1.1 提供了摘要认证(Digest 认证)。其原理大致为:服务端向浏览器发送一个 nonce 随机数,浏览器将账号、密码和 nonce 等参数进行 MD5 加密后传给服务端(同时传递账号数据,但不直接传递密码)。服务端获取到账号后,从数据库取出密码同样进行 MD5 加密,若加密后的值与浏览器传来的值一致,则视为认证成功。

摘要认证不再明文传输密码,具备防重放攻击和避免报文被篡改的能力,但通常需要配合 HTTPS 使用。

Session-Cookie

Session-Cookie 认证是一种利用服务端 Session(会话)和浏览器 Cookie 来实现前后端通信认证的模式。

什么是 Cookie

HTTP 是一种无状态协议。当服务端接收到客户端首次请求后,会设置对应的 Cookie。随后,浏览器在后续请求中携带该 Cookie,服务端即可识别当前客户端的状态。

Cookie 的特点:

  • Cookie 存储在客户端,可能被篡改,安全性相对较低。
  • 有大小限制,通常限制在 4KB 左右。
  • Android 和 iOS 系统对 Cookie 的支持情况不佳。
  • Cookie 存在跨域限制。

什么是 Session

Session 的抽象概念是会话。在通信过程中,为了实现中断或继续操作,将用户与服务器之间的交互进行一种抽象处理。

Session 的一般流程是:服务端接收到客户端首次请求后,创建一个 Session 来跟踪用户会话,同时向客户端返回一个 Session ID。后续客户端请求时携带该 Session ID,服务端即可找到对应的 Session,此时双方的通信即变为有状态。

Session 特点:

  • Session 数据保存在服务端,安全性较高。
  • Session 数据大小可以超过 4KB,存储数据量较大。

Session-Cookie 流程

在 Session 流程中通常会设置 Session ID,且该 ID 一般保存在浏览器的 Cookie 中。接下来查看整体流程。

概念介绍

以下是 Session-Cookie 的认证步骤解析:

  • 浏览器发送登录请求。
  • 服务端校验账号密码,校验通过后生成 Session 和 Session ID。Session 保存在 Session 服务器中(通常保存在内存或 Redis 服务器)。随后服务端返回数据给浏览器,同时设置一个包含 Session ID 的 Cookie。
  • 浏览器请求资源时,一般会自动带上包含 Session ID 的 Cookie。
  • 服务端获取到 Session ID,通过 Session 服务器校验 Session。若校验成功,服务端则处理数据逻辑。
  • 服务端返回数据给浏览器。

简单代码示例

const express = require("express");
const app = express();
const bodyParser = require("body-parser");
const port = 3000;
const session = require("express-session");
app.use(bodyParser());
app.use(
  session({
    key: 'SESSION_ID',
    secret: "your_secret_key",
    resave: false,
    saveUninitialized: false,
    cookie: { maxAge: 1000 * 60 * 60 * 8, signed: true },
  })
);
app.get("/", async function (req, res) {
  res.send(req.session);
});
app.get("/login", async function (req, res) {
  const authInfo = {
    id: '1',
    username: 'user',
  }
  const isValid = true
  if (isValid) {
    req.session.authInfo = authInfo
    res.send({
      success: true,
      info: "登录成功",
    });
  } else {
    res.send({
      success: false,
      info: "登录失败",
    });
  }
});
app.listen(port, () => {
  console.log(`node listening at http://localhost:${port}`);
});

使用 node 起好服务器后,先访问 /login,再访问首页 /,可以看到首页输出用户名。同时打开 F12 开发者工具,在 Cookie 中可以查看到 SESSION_ID 的数据。

小结

优点:

  • Cookie 简单易用。
  • Session 数据保存在服务端,安全性较高。
  • 支持 Session 管理,能够主动注销 Session。
  • 只需后端操作,前端无感知。

缺点:

  • 依赖 Cookie,若禁用 Cookie 则无法使用。
  • 由于使用了 Cookie,可能存在 CSRF(跨站请求伪造)攻击风险。
  • Session 存在于服务端,当用户量巨大时,服务端开销增加,性能可能下降。
  • 对移动端的支持性不友好。

使用场景:

  • 一般中大型网站均适用。

Token

在上述介绍中,我们了解了 Session-Cookie 的一些缺点,以及 Session 的维护给服务端带来的困扰(必须寻找地方存放它,又要考虑分布式问题)。因此,Token 方案应运而生。

什么是 Token

Token 是一个令牌。客户端访问服务器时,验证通过后服务端会为其签发一张令牌。之后,客户端即可携带该令牌访问服务器,服务端只需验证令牌的有效性即可。

一般 Token 的组成:

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

Token 认证流程

概念介绍

以下是 Token 的认证步骤解析:

  • 客户端发送登录请求。
  • 服务端校验账号密码,生成 Token,并返回给客户端。
  • 收到 Token 以后需要将其存储起来,Web 端一般会存放在 localStorage 或 Cookie 中。
  • 客户端请求 API 资源时,将 Token 通过 HTTP 请求头 Authorization 字段或其他方式发送给服务端。
  • 服务端拿到 Token,进行解密和签名校验。通过校验则返回数据,否则返回 401。

Token 的优缺点

优点:

  • 服务端无状态化、可扩展性好:Token 自身包含了其所标识用户的相关信息,这有利于在多个服务间共享用户状态。
  • 安全性好,可以避免 CSRF 攻击。
  • 支持跨域调用。

缺点:

  • 性能问题:服务端需要对 Token 进行加解密等操作,因此会更消耗性能。
  • 有效期短:为了避免 Token 被盗用,一般 Token 的有效期设置得较短,因此引入了 Refresh Token。
  • 相比于 Session-Cookie,需要前后端配合处理。

Refresh Token

业务接口用来鉴权的 Token 称为 Access Token。为了安全性,Access Token 的有效期通常设置得比较短。Access Token 过期后,需要用户重新登录,但这种体验较差。

因此引入了 Refresh Token,可以使用 Refresh Token 去获取 Access Token。

  • Access Token:用来访问业务接口,由于有效期足够短,盗用风险小。

  • Refresh Token:用来获取 Access Token,有效期可以长一些,通过独立服务和严格的请求方式增加安全性。

Refresh Token 的使用流程是:在服务器校验 Token 发现过期后,客户端可以使用 Refresh Token 发起请求,获取新的 Access Token 和 Refresh Token。

JSON Web Token(JWT)

在上述 Token 中,一般仅包含 uid 信息。若需更多登录信息和其他数据,则需查询数据库。每次查询数据库会带来性能消耗,因此业界常用的 JWT 方案由此产生。

JWT 是 Auth0 提出的通过对 JSON 进行加密签名来实现授权验证的方案。其特点是自包含的,用户信息和认证信息整合在一起,无需像 Cookie-Session 那样需要 Session 服务器,或像普通 Token 那样访问数据库获取用户信息。

JWT 本质上就是一组字串,通过(.)切分成三个为 Base64 编码的部分:

  • Header:描述 JWT 的元数据,定义了生成签名的算法以及 Token 的类型。
  • Payload:用来存放实际需要传递的数据。JWT 规定了 7 个官方字段,例如 iss、exp 等,还可以自定义数据。
  • Signature(签名):服务器通过 Payload、Header 和一个密钥 (Secret) 使用 Header 里面指定的签名算法(默认是 HMAC SHA 256)生成。

JWT 通常格式如下:xxxxx.yyyyy.zzzzz。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJuYW1lIjoieGlhb21pbmciLCJkYXRhIjoiPT09PT09PT09PT09PSIsImlhdCI6MTY3OTgwNDA1NywiZXhwIjoxNjc5ODA0MTE3fQ
.FdJ6UD4Ff5zOz83f4hRDh1C86kN5f8aO_KeEtIwt3cM

JWT 认证流程

概念介绍

其实 JWT 的认证流程与普通 Token 的认证流程相似,只是无需再单独去查询数据库查找用户信息。

JWT 实例

const { expressjwt: jwt } = require('express-jwt')
const express = require('express')
const app = express()
const jsonwebtoken = require('jsonwebtoken')
const secretOrPrivateKey = 'hello' //加密token 校验token时要使用
app.use(
  jwt({
    secret: secretOrPrivateKey,
    algorithms: ['HS256'],
  }).unless({
    path: ['/getToken'], //除了这个地址,其他的URL都需要验证
  })
)
app.use(function (err, req, res, next) {
  if (err.name === 'UnauthorizedError') {
    res.status(401).send('invalid token...')
  }
})
app.get('/getToken', function (req, res) {
  res.json({
    result: 'ok',
    token: jsonwebtoken.sign(
      {
        name: 'xiaoming',
        data: '=============',
      },
      secretOrPrivateKey,
      {
        expiresIn: 60 * 1,
      }
    ),
  })
})
app.get('/getData', function (req, res) {
  res.send('data')
})
app.listen(3000)

服务启动后,访问 /getToken 获取 JWT,然后在 Postman 中请求 /getData,Header 部分加上 Authorization: Bearer your jwt,例如 Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoieGlhb21pbmciLCJkYXRhIjoiPT09PT09PT09PT09PSIsImlhdCI6MTY3OTgwNjkyOCwiZXhwIjoxNjc5ODA2OTg4fQ.qFOT9IS_T1ZNsWWheRXP9MxYPh1l3SBGWLtp8ocnKAE。

JWT 的优缺点

优点:

  • 不需要在服务端保存会话信息,因此易于应用的扩展。
  • JWT 中的 Payload 负载可以存储常用信息,用于信息交换。有效地使用 JWT,可以降低服务端查询数据库的次数。

缺点:

  • 请求头体积较大,当 Payload 数据量大的时候,请求头体积也会相应增大。
  • JWT 默认是不加密的,因此 Payload 一般不存放敏感信息,不过也可以再次加密。
  • 到期问题:JWT 一旦签发后,除非到了过期时间,否则一直有效,服务端无法主动注销。

使用场景:

  • 一般对安全要求不高、对负载要求高的场景均可使用 JWT。安全敏感的场景推荐使用 token + redis 方案。
  • 单点登录

Oauth 2.0

OAuth 这种登录方式想必大家都使用过。例如,当我们想登录某个网站时,通常会发现可以通过第三方的 QQ 或者微信登录,这就是使用了 OAuth。

OAuth 是一个开放标准,允许用户授权第三方网站访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方网站。常见的提供 OAuth 认证服务的厂商包括:支付宝、QQ、微信、微博。

OAuth 认证流程

概念介绍

以下是 OAuth 的认证步骤解析:

  • 客户端发起使用第三方登录,服务端携带 client_id 直接重定向到授权服务器登录页面,授权服务器要求客户端登录。
  • 客户端完成第三方登录并同意授权后,授权服务器重定向回服务端,并携带授权码 code。服务器随后携带 client_id、client_secret、code 向授权服务器请求令牌。
  • 授权服务器通过认证,并返回令牌。
  • 服务端用令牌向授权服务器请求用户基本信息,授权服务器认证令牌通过后返回数据。
  • 服务端返回用户信息给客户端。

使用 github 登录示例

准备工作:

1、创建 OAuth App

概念介绍

2、填写基本信息

概念介绍

3、获取 client_id 和 client_secret

概念介绍

代码示例

const express = require('express')
const app = express()
const querystring = require('querystring')
const axios = require('axios')
// GitHub登录参数配置;配置授权应用生成的Client ID和Client Secret
const config = {
  client_id: 'xxx',
  client_secret: 'xxxxxx'
}
// 登录接口
app.get('/github/login', function (req, res) {
  // 重定向到GitHub认证接口,并配置参数
  let path = 'https://github.com/login/oauth/authorize?client_id=' + config.client_id
  // 转发到授权服务器
  res.redirect(path)
})
// GitHub授权登录成功回调,地址必须与GitHub配置的回调地址一致
app.get('/passport/github/callback', async function (req, res) {
  console.log('callback...')
  // 服务器认证成功,回调带回认证状态code
  const code = req.query.code
  const params = {
    client_id: config.client_id,
    client_secret: config.client_secret,
    code: code
  }
  // 申请令牌token
  let tokenRes = await axios.post('https://github.com/login/oauth/access_token', params)
  const access_token = querystring.parse(tokenRes.data).access_token
  // 根据token获取用户信息
  userRes = await axios.get(`https://api.github.com/user`, {
    headers: {
      'Authorization': 'token ' + access_token
    }
  })
  // 渲染页面
  res.end(`
    <h1>Hello ${userRes.data.login}</h1>
    <img src="${userRes.data.avatar_url}" alt="">
  `)
})
app.listen(7001, () => {
  console.log('listening port at 7001...')
})

服务启动后,访问 /github/login,后续会跳转 github 登录授权,完成后即可看到你的 github 用户名和头像。

总结

登录的认证授权方式有很多,上述讲到的都是一些常见的方案。当前方案的具体细节实施,各个项目方还是会有所差异。

除了上述内容外,认证授权这块还有单点登录(SSO)、扫描登录、手机号一键登录等方式,后续有机会再讲。

以上就是JS前端认证授权技巧归纳总结的详细内容,更多关于JS前端认证授权的资料请关注本站其它相关文章!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章