前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • 基础篇

    • 环境搭建
    • node部署
    • 基础应用
  • 内置模块

    • 1.0 本地路径处理 path
    • 2.0 文件系统操作 fs
    • 3.1 基础调试 console
    • 3.2 本地调试远程服务器上的Node代码
    • 4.1 网络服务 http
    • 4.2 网络服务 http res
    • 4.3 网络服务 http req
    • 4.4 网络服务 http server
    • 4.5 网络服务 http client
    • 4.6 网络服务 https
    • 4.7 网络TCP net
    • 4.8 网络UDP dgram
    • 4.9 域名解析 dns
    • 5.0 网络地址解析 url
    • 5.1 URL查询字符串 querystring
    • 6.1 流操作 stream
    • 6.2 逐行读取 readline
    • 7.1 进程相关 process
    • 7.2 子进程 child
    • 8.1 二进制数据 buffer
    • 8.2 二进制解码 string_decoder
    • 9.1 事件机制 events
    • 9.2 实用工具模块 util
    • 9.3 数据加密 crypto
    • 9.4 MD5入门介绍及crypto模块的应用
    • 9.4 资源压缩 zlib
    • 9.5 集群 cluster
    • 9.6 v8
  • 进阶篇

    • 5分钟入门非对称加密用法
    • cluster
    • cookie_parser深入
    • crypto模块之理论篇
    • express+cookie_parser签名机制深入剖析
    • express+session实现简易身份认证
    • https
    • log4js入门实例
    • node8_napi
    • 使用 async 控制并发
    • 使用 eventproxy 控制并发
    • 使用 superagent 与 cheerio 完成简单爬虫
    • 基于express+muter的文件上传
    • 将图片转成datauri嵌入到html
    • 常用中间件 body_parser 实现解析
    • 日志模块morgan
    • 服务端字符编解码&乱码处理 charset_enc_dec
    • 测试用例mocha,should,istanbul
    • 调试日志打印debug模块
  • Express

    • 1.1 Express概览篇
    • 1.2 Express
  • Koa2

    • 1.0 koa2概览篇
    • 1.1 快速开始
    • 1.2 async await使用
    • 1.3 koa2简析结构
    • 1.4 koa中间件开发与使用
    • 10.1 单元测试
    • 11.1 开发debug
    • 12.1 快速启动
    • 12.2 框架设计
    • 12.3 分层操作
    • 12.4 数据库设计
    • 12.5 路由设计
    • 12.6 webpack4环境搭建
    • 12.7 使用react
    • 12.8 登录注册功能实现
    • 12.9 session登录态判断处理
    • 13.1 import export使用
    • 2.1 原生koa2实现路由
    • 2.2 koa router中间
    • 3.1 GET请求数据获取
    • 3.2 POST请求数据获取
    • 3.3 koa bodyparser中间件
    • 4.1 原生koa2实现静态资源服务器
    • 4.2 koa static中间件
    • 5.1 koa2使用cookie
    • 5.2 koa2实现session
    • 6.1 koa2加载模板引擎
    • 6.2 ejs模板引擎
    • 7.1 busboy模块
    • 7.2 上传文件简单实现
    • 7.3 异步上传图片实现
    • 8.1 mysql模块
    • 8.2 async await封装使用mysql
    • 8.3 项目建表初始化
    • 9.1 原生koa2实现JSONP
    • 9.2 koa jsonp中间件
  • 其他

    • 操作数据库
    • Session 与 Token
    • Cookie、Session、Token、JWT
    • Socket

# Cookie、Session、Token、JWT

30 秒速记

  • 四个东西不在一个层级:Cookie 是浏览器存储和自动携带机制,Session 是服务端存状态的方案,Token 是凭证,JWT 是 Token 的一种格式
  • 经典组合:Session 数据在服务端,session id 装在 Cookie 里;JWT 也可以装在 Cookie 里
  • Cookie 三个安全属性:HttpOnly 防脚本读、Secure 只走 HTTPS、SameSite 挡跨站请求带 Cookie
  • JWT 校验别只验签名:限定算法,检查 exp、iss、aud
  • Refresh Token 比 Access Token 值钱,要轮换、能撤销

这四个概念最容易被并列着比,其实它们不在一个层级:Cookie 是载体,Session 是存储方案,Token 是凭证,JWT 是凭证的一种格式。 打个比方,Cookie 是钱包,session id 和 JWT 都是可以放进钱包的卡:session id 像储物柜号码牌,东西存在服务端;JWT 像盖了章的身份证明,信息就写在卡上。所以「用 Session 还是 JWT」是在比存储方案,「放 Cookie 还是放请求头」是在比怎么传,这两件事要分开说。

理解「Cookie、Session、Token、JWT」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。

工程中还要验证退出码、资源清理和异常输入。属于 security 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。

把四个概念放在一次请求里看,层级就很清楚:

# 方案 A:Session + Cookie
Set-Cookie: sid=s%3Aabc123.sig; HttpOnly; Secure; SameSite=Lax   ← 登录响应
Cookie: sid=s%3Aabc123.sig                                       ← 之后每次请求,浏览器自动带
# 服务端拿 abc123 去 Redis 查 { uid: 42, role: 'admin' }

# 方案 B:JWT + Authorization 头
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1aWQiOjQyfQ.sig    ← 前端代码手动带
# 服务端不查库,验签名后直接得到 { uid: 42 }

# 方案 C:JWT + Cookie
Cookie: access_token=eyJhbGciOiJIUzI1NiJ9.eyJ1aWQiOjQyfQ.sig
@前端进阶之旅: 代码已经复制到剪贴板

选型可以拆成两个独立问题。第一个是状态存哪:存服务端(Session)好撤销、好控制,但多实例要共享存储;存客户端(JWT)好扩容,但难撤销。第二个是怎么传:Cookie 浏览器自动带,配上 HttpOnly 能防脚本偷,但要处理 CSRF;请求头手动带,不怕 CSRF,但 Token 要放在脚本能读到的地方,怕 XSS。

校验 JWT 时只验签名是不够的。要固定允许的算法(比如只认 HS256 或 RS256),防止有人把 alg 改成 none 或者用公钥冒充 HMAC 密钥;还要检查 exp 没过期、iss 是自己的签发方、aud 是给当前服务的。Refresh Token 有效期长,泄露损失更大,每次刷新都换一张新的,旧的作废,发现旧的被再次使用就说明泄露了,把这个用户的整条令牌链都撤销。

面试官追问

追问 1页面刷新后还是登录状态,能说明用的是 JWT 吗?
参考回答

不能,Session 加 Cookie、JWT 放 localStorage 都能做到。打开 Network 看请求带的是 Cookie: connect.sid=... 还是 Authorization: Bearer eyJ...,以 eyJ 开头基本就是 JWT。

追问 2JWT 放进 Cookie 里,那它算 Cookie 认证还是 Token 认证?
参考回答

这么问本身就混了层级。凭证是 JWT,传输载体是 Cookie,服务端不查会话存储,只验签名。安全上要同时考虑 Cookie 的 CSRF 问题。

追问 3设了 HttpOnly 是不是就不怕 XSS 了?
参考回答

不是。HttpOnly 只让脚本读不到 Cookie,可攻击脚本可以直接在你页面里发请求,浏览器照样自动带上 Cookie。它能防偷走凭证,防不了借用凭证,根本还是要堵住 XSS。

追问 4接口要同时给浏览器和后台脚本调,用哪种方案?
参考回答

脚本没有浏览器的 Cookie 机制,用 Authorization 头带 Token 更通用。浏览器端可以继续用 Cookie,服务端中间件两种来源都认,统一解析成 req.user。

# 什么是认证(Authentication)

30 秒速记

  • 认证(Authentication)回答「你是谁」:证明你就是这个账号的主人
  • 类比:指纹打卡,指纹和录入的对得上才算你本人
  • 互联网常见方式:账号密码、短信验证码、邮箱登录链接、扫码、第三方登录
  • 验证码和邮箱链接的逻辑是:能收到 = 你控制这个手机号或邮箱 = 账号主人
  • 别和授权混:授权是「你能做什么」,先认证再授权,失败分别是 401 和 403

认证就是确认「你是你」,系统要先弄清楚请求是谁发的。 最好懂的例子是指纹打卡,按上去和系统里录入的一致,就认定是你本人。网站上换成账号密码、短信验证码、邮箱登录链接这些方式,后两种的逻辑其实是「谁能收到验证码,谁就是这个手机号的主人」。面试里常和授权一起问,记住一句:认证管你是谁,授权管你能干什么,接口层面认证失败回 401,认证过了但没权限回 403。

  • 通俗地讲就是验证当前用户的身份,证明“你是你自己”(比如:你每天上下班打卡,都需要通过指纹打卡,当你的指纹和系统里录入的指纹相匹配时,就打卡成功)
  • 互联网中的认证:
    • 用户名密码登录
    • 邮箱发送登录链接
    • 手机号接收验证码
    • 只要你能收到邮箱/验证码,就默认你是账号的主人

面试官追问

追问 1用户给了相册权限,能不能当他已经登录?
参考回答

不能,那是授权,而且是授权给 App 访问手机能力,和账号身份没关系。要看个人资料,还是得先登录认证。

追问 2短信验证码登录,服务端至少要做哪些校验?
参考回答

验证码要和手机号绑定、设有效期(比如 5 分钟)、用一次就作废,再限制错误次数和发送频率,不然 4 位、6 位验证码都能被暴力试出来。

追问 3401 和 403 怎么区分?
参考回答

401 是「我不知道你是谁」,没登录或凭证无效,前端该引导登录;403 是「知道你是谁,但你没这个权限」,重新登录也没用。

追问 4同时支持密码、短信、邮箱三种登录,后端怎么设计比较干净?
参考回答

三种入口各自完成身份校验,校验通过后走同一个签发凭证的函数,后续接口完全不关心用户是怎么登录的。

# 什么是授权(Authorization)

30 秒速记

  • 授权(Authorization)回答「你能做什么」,发生在认证之后
  • 两种场景别混:用户授权第三方应用访问自己的资源(OAuth、小程序获取头像),以及系统内部的权限控制(角色、菜单、按钮)
  • 授权要按资源分开给,给了头像不等于给了位置
  • 实现上可以用 Session、Token、OAuth,它们是载体,权限模型(RBAC 之类)才是核心
  • 前端隐藏按钮只是体验,真正的权限判断必须在服务端

授权管的是「你能做什么」,认证确认身份之后才轮到它。 日常说授权其实有两种:一种是用户把自己的资源开放给第三方,比如小程序弹窗问能不能获取头像昵称,或者用微信登录第三方网站,这就是 OAuth 那一套;另一种是系统内部的权限,比如普通员工看不到财务菜单。不管哪种,都要按资源单独授权,而且最终判断一定在服务端,前端隐藏按钮只是为了不让用户点了才报错。

  • 用户授予第三方应用访问该用户某些资源的权限
    • 你在安装手机应用的时候,APP 会询问是否允许授予权限(访问相册、地理位置等权限)
    • 你在访问微信小程序时,当登录时,小程序会询问是否允许授予权限(获取昵称、头像、地区、性别等个人信息)
  • 实现授权的方式有:cookie、session、token、OAuth

面试官追问

追问 1用户已经登录了,小程序能直接读他的头像和位置吗?
参考回答

不能,登录只证明他是谁。头像、位置这些要单独申请授权,用户拒绝了也得给一条能继续用的路。

追问 2之前用户授权过头像,新功能要定位,能复用之前的授权吗?
参考回答

不能,授权是按资源给的,位置要单独申请。偷偷扩大范围既违反平台规范,用户知道了也会直接卸载。

追问 3管理后台前端把没权限的按钮都隐藏了,后端还要校验吗?
参考回答

必须校验。用户可以直接用 curl 或者改前端代码调接口,前端隐藏只是体验优化,每个接口在服务端都要查一次当前用户的角色权限。

追问 4用户已登录,访问定位页却报无权限,怎么判断是认证还是授权问题?
参考回答

先看接口返回码:401 是身份没认出来,查凭证;403 是身份对但没权限,查角色配置或者用户是否拒绝了位置授权。别一律让用户重新登录。

# 什么是凭证(Credentials)

30 秒速记

  • 凭证(Credentials)= 证明你身份的那个东西,认证和授权都靠它
  • 登录前是账号密码、验证码;登录后服务端换给你一个凭证,比如 session id 或 Token
  • 游客模式能看,登录模式能点赞收藏,区别就在请求里有没有带有效凭证
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • 基础篇

    • 环境搭建
    • node部署
    • 基础应用
  • 内置模块

    • 1.0 本地路径处理 path
    • 2.0 文件系统操作 fs
    • 3.1 基础调试 console
    • 3.2 本地调试远程服务器上的Node代码
    • 4.1 网络服务 http
    • 4.2 网络服务 http res
    • 4.3 网络服务 http req
    • 4.4 网络服务 http server
    • 4.5 网络服务 http client
    • 4.6 网络服务 https
    • 4.7 网络TCP net
    • 4.8 网络UDP dgram
    • 4.9 域名解析 dns
    • 5.0 网络地址解析 url
    • 5.1 URL查询字符串 querystring
    • 6.1 流操作 stream
    • 6.2 逐行读取 readline
    • 7.1 进程相关 process
    • 7.2 子进程 child
    • 8.1 二进制数据 buffer
    • 8.2 二进制解码 string_decoder
    • 9.1 事件机制 events
    • 9.2 实用工具模块 util
    • 9.3 数据加密 crypto
    • 9.4 MD5入门介绍及crypto模块的应用
    • 9.4 资源压缩 zlib
    • 9.5 集群 cluster
    • 9.6 v8
  • 进阶篇

    • 5分钟入门非对称加密用法
    • cluster
    • cookie_parser深入
    • crypto模块之理论篇
    • express+cookie_parser签名机制深入剖析
    • express+session实现简易身份认证
    • https
    • log4js入门实例
    • node8_napi
    • 使用 async 控制并发
    • 使用 eventproxy 控制并发
    • 使用 superagent 与 cheerio 完成简单爬虫
    • 基于express+muter的文件上传
    • 将图片转成datauri嵌入到html
    • 常用中间件 body_parser 实现解析
    • 日志模块morgan
    • 服务端字符编解码&乱码处理 charset_enc_dec
    • 测试用例mocha,should,istanbul
    • 调试日志打印debug模块
  • Express

    • 1.1 Express概览篇
    • 1.2 Express
  • Koa2

    • 1.0 koa2概览篇
    • 1.1 快速开始
    • 1.2 async await使用
    • 1.3 koa2简析结构
    • 1.4 koa中间件开发与使用
    • 10.1 单元测试
    • 11.1 开发debug
    • 12.1 快速启动
    • 12.2 框架设计
    • 12.3 分层操作
    • 12.4 数据库设计
    • 12.5 路由设计
    • 12.6 webpack4环境搭建
    • 12.7 使用react
    • 12.8 登录注册功能实现
    • 12.9 session登录态判断处理
    • 13.1 import export使用
    • 2.1 原生koa2实现路由
    • 2.2 koa router中间
    • 3.1 GET请求数据获取
    • 3.2 POST请求数据获取
    • 3.3 koa bodyparser中间件
    • 4.1 原生koa2实现静态资源服务器
    • 4.2 koa static中间件
    • 5.1 koa2使用cookie
    • 5.2 koa2实现session
    • 6.1 koa2加载模板引擎
    • 6.2 ejs模板引擎
    • 7.1 busboy模块
    • 7.2 上传文件简单实现
    • 7.3 异步上传图片实现
    • 8.1 mysql模块
    • 8.2 async await封装使用mysql
    • 8.3 项目建表初始化
    • 9.1 原生koa2实现JSONP
    • 9.2 koa jsonp中间件
  • 其他

    • 操作数据库
    • Session 与 Token
    • Cookie、Session、Token、JWT
      • 什么是认证(Authentication)
      • 什么是授权(Authorization)
      • 什么是凭证(Credentials)
      • 什么是 Cookie
      • 什么是 Session
      • Cookie 和 Session 的区别
      • 什么是 Token(令牌)
        • Acesss Token
        • Refresh Token
      • Token 和 Session 的区别
      • 什么是 JWT
      • Token 和 JWT 的区别
      • 常见的前后端鉴权方式
      • 常见的加密算法
      • 常见问题
      • 分布式架构下 session 共享方案
      • 可运行示例:严格校验 JWT 声明的边界
    • Socket
完整面试题地址:
作者:程序员poetry
扫码关注作者公众号:「前端进阶之旅」 每天分享技术干货
前端进阶之旅公众号二维码

Cookie、Session、Token、JWT|Nodejs专题系列

# Cookie、Session、Token、JWT

30 秒速记

  • 四个东西不在一个层级:Cookie 是浏览器存储和自动携带机制,Session 是服务端存状态的方案,Token 是凭证,JWT 是 Token 的一种格式
  • 经典组合:Session 数据在服务端,session id 装在 Cookie 里;JWT 也可以装在 Cookie 里
  • Cookie 三个安全属性:HttpOnly 防脚本读、Secure 只走 HTTPS、SameSite 挡跨站请求带 Cookie
  • JWT 校验别只验签名:限定算法,检查 exp、iss、aud
  • Refresh Token 比 Access Token 值钱,要轮换、能撤销

这四个概念最容易被并列着比,其实它们不在一个层级:Cookie 是载体,Session 是存储方案,Token 是凭证,JWT 是凭证的一种格式。 打个比方,Cookie 是钱包,session id 和 JWT 都是可以放进钱包的卡:session id 像储物柜号码牌,东西存在服务端;JWT 像盖了章的身份证明,信息就写在卡上。所以「用 Session 还是 JWT」是在比存储方案,「放 Cookie 还是放请求头」是在比怎么传,这两件事要分开说。

理解「Cookie、Session、Token、JWT」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。

工程中还要验证退出码、资源清理和异常输入。属于 security 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。

把四个概念放在一次请求里看,层级就很清楚:

# 方案 A:Session + Cookie
Set-Cookie: sid=s%3Aabc123.sig; HttpOnly; Secure; SameSite=Lax   ← 登录响应
Cookie: sid=s%3Aabc123.sig                                       ← 之后每次请求,浏览器自动带
# 服务端拿 abc123 去 Redis 查 { uid: 42, role: 'admin' }

# 方案 B:JWT + Authorization 头
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1aWQiOjQyfQ.sig    ← 前端代码手动带
# 服务端不查库,验签名后直接得到 { uid: 42 }

# 方案 C:JWT + Cookie
Cookie: access_token=eyJhbGciOiJIUzI1NiJ9.eyJ1aWQiOjQyfQ.sig
@前端进阶之旅: 代码已经复制到剪贴板

选型可以拆成两个独立问题。第一个是状态存哪:存服务端(Session)好撤销、好控制,但多实例要共享存储;存客户端(JWT)好扩容,但难撤销。第二个是怎么传:Cookie 浏览器自动带,配上 HttpOnly 能防脚本偷,但要处理 CSRF;请求头手动带,不怕 CSRF,但 Token 要放在脚本能读到的地方,怕 XSS。

校验 JWT 时只验签名是不够的。要固定允许的算法(比如只认 HS256 或 RS256),防止有人把 alg 改成 none 或者用公钥冒充 HMAC 密钥;还要检查 exp 没过期、iss 是自己的签发方、aud 是给当前服务的。Refresh Token 有效期长,泄露损失更大,每次刷新都换一张新的,旧的作废,发现旧的被再次使用就说明泄露了,把这个用户的整条令牌链都撤销。

面试官追问

追问 1页面刷新后还是登录状态,能说明用的是 JWT 吗?
参考回答

不能,Session 加 Cookie、JWT 放 localStorage 都能做到。打开 Network 看请求带的是 Cookie: connect.sid=... 还是 Authorization: Bearer eyJ...,以 eyJ 开头基本就是 JWT。

追问 2JWT 放进 Cookie 里,那它算 Cookie 认证还是 Token 认证?
参考回答

这么问本身就混了层级。凭证是 JWT,传输载体是 Cookie,服务端不查会话存储,只验签名。安全上要同时考虑 Cookie 的 CSRF 问题。

追问 3设了 HttpOnly 是不是就不怕 XSS 了?
参考回答

不是。HttpOnly 只让脚本读不到 Cookie,可攻击脚本可以直接在你页面里发请求,浏览器照样自动带上 Cookie。它能防偷走凭证,防不了借用凭证,根本还是要堵住 XSS。

追问 4接口要同时给浏览器和后台脚本调,用哪种方案?
参考回答

脚本没有浏览器的 Cookie 机制,用 Authorization 头带 Token 更通用。浏览器端可以继续用 Cookie,服务端中间件两种来源都认,统一解析成 req.user。

# 什么是认证(Authentication)

30 秒速记

  • 认证(Authentication)回答「你是谁」:证明你就是这个账号的主人
  • 类比:指纹打卡,指纹和录入的对得上才算你本人
  • 互联网常见方式:账号密码、短信验证码、邮箱登录链接、扫码、第三方登录
  • 验证码和邮箱链接的逻辑是:能收到 = 你控制这个手机号或邮箱 = 账号主人
  • 别和授权混:授权是「你能做什么」,先认证再授权,失败分别是 401 和 403

认证就是确认「你是你」,系统要先弄清楚请求是谁发的。 最好懂的例子是指纹打卡,按上去和系统里录入的一致,就认定是你本人。网站上换成账号密码、短信验证码、邮箱登录链接这些方式,后两种的逻辑其实是「谁能收到验证码,谁就是这个手机号的主人」。面试里常和授权一起问,记住一句:认证管你是谁,授权管你能干什么,接口层面认证失败回 401,认证过了但没权限回 403。

  • 通俗地讲就是验证当前用户的身份,证明“你是你自己”(比如:你每天上下班打卡,都需要通过指纹打卡,当你的指纹和系统里录入的指纹相匹配时,就打卡成功)
  • 互联网中的认证:
    • 用户名密码登录
    • 邮箱发送登录链接
    • 手机号接收验证码
    • 只要你能收到邮箱/验证码,就默认你是账号的主人

面试官追问

追问 1用户给了相册权限,能不能当他已经登录?
参考回答

不能,那是授权,而且是授权给 App 访问手机能力,和账号身份没关系。要看个人资料,还是得先登录认证。

追问 2短信验证码登录,服务端至少要做哪些校验?
参考回答

验证码要和手机号绑定、设有效期(比如 5 分钟)、用一次就作废,再限制错误次数和发送频率,不然 4 位、6 位验证码都能被暴力试出来。

追问 3401 和 403 怎么区分?
参考回答

401 是「我不知道你是谁」,没登录或凭证无效,前端该引导登录;403 是「知道你是谁,但你没这个权限」,重新登录也没用。

追问 4同时支持密码、短信、邮箱三种登录,后端怎么设计比较干净?
参考回答

三种入口各自完成身份校验,校验通过后走同一个签发凭证的函数,后续接口完全不关心用户是怎么登录的。

# 什么是授权(Authorization)

30 秒速记

  • 授权(Authorization)回答「你能做什么」,发生在认证之后
  • 两种场景别混:用户授权第三方应用访问自己的资源(OAuth、小程序获取头像),以及系统内部的权限控制(角色、菜单、按钮)
  • 授权要按资源分开给,给了头像不等于给了位置
  • 实现上可以用 Session、Token、OAuth,它们是载体,权限模型(RBAC 之类)才是核心
  • 前端隐藏按钮只是体验,真正的权限判断必须在服务端

授权管的是「你能做什么」,认证确认身份之后才轮到它。 日常说授权其实有两种:一种是用户把自己的资源开放给第三方,比如小程序弹窗问能不能获取头像昵称,或者用微信登录第三方网站,这就是 OAuth 那一套;另一种是系统内部的权限,比如普通员工看不到财务菜单。不管哪种,都要按资源单独授权,而且最终判断一定在服务端,前端隐藏按钮只是为了不让用户点了才报错。

  • 用户授予第三方应用访问该用户某些资源的权限
    • 你在安装手机应用的时候,APP 会询问是否允许授予权限(访问相册、地理位置等权限)
    • 你在访问微信小程序时,当登录时,小程序会询问是否允许授予权限(获取昵称、头像、地区、性别等个人信息)
  • 实现授权的方式有:cookie、session、token、OAuth

面试官追问

追问 1用户已经登录了,小程序能直接读他的头像和位置吗?
参考回答

不能,登录只证明他是谁。头像、位置这些要单独申请授权,用户拒绝了也得给一条能继续用的路。

追问 2之前用户授权过头像,新功能要定位,能复用之前的授权吗?
参考回答

不能,授权是按资源给的,位置要单独申请。偷偷扩大范围既违反平台规范,用户知道了也会直接卸载。

追问 3管理后台前端把没权限的按钮都隐藏了,后端还要校验吗?
参考回答

必须校验。用户可以直接用 curl 或者改前端代码调接口,前端隐藏只是体验优化,每个接口在服务端都要查一次当前用户的角色权限。

追问 4用户已登录,访问定位页却报无权限,怎么判断是认证还是授权问题?
参考回答

先看接口返回码:401 是身份没认出来,查凭证;403 是身份对但没权限,查角色配置或者用户是否拒绝了位置授权。别一律让用户重新登录。

# 什么是凭证(Credentials)

30 秒速记

  • 凭证(Credentials)= 证明你身份的那个东西,认证和授权都靠它
  • 登录前是账号密码、验证码;登录后服务端换给你一个凭证,比如 session id 或 Token
  • 游客模式能看,登录模式能点赞收藏,区别就在请求里有没有带有效凭证
  • 凭证必须由服务端签发、服务端校验,前端自己存的 isLogin = true 不算

凭证就是你出示给服务端证明身份的那个东西,类似进公司要刷的工牌。 拿掘金这类网站举例,游客能看文章,但点赞收藏就要登录;登录成功后服务端发一个 Token(或者 session id)给浏览器,之后每次请求带着它,服务端认出你是谁,就放开那些功能。关键在于凭证一定是服务端发、服务端验的,前端自己记个「已登录」的状态只能控制界面显示,证明不了任何事。

实现认证和授权的前提是需要一种媒介(证书) 来标记访问者的身份

在互联网应用中,一般网站(如掘金)会有两种模式,游客模式和登录模式。游客模式下,可以正常浏览网站上面的文章,一旦想要点赞/收藏/分享文章,就需要登录或者注册账号。当用户登录成功后,服务器会给该用户使用的浏览器颁发一个令牌(token),这个令牌用来表明你的身份,每次浏览器发送请求时会带上这个令牌,就可以使用游客模式下无法使用的功能。

面试官追问

追问 1文章能游客访问,前端觉得点赞接口也可以不要 Token,行吗?
参考回答

不行。浏览可以公开,点赞要知道是谁点的、防止刷赞,服务端必须要求凭证,没带就回 401。

追问 2前端只存一个 isLogin 布尔值,不带 Token,能不能省点流量?
参考回答

不能,那个值用户在控制台一改就是 true,服务端根本无法分辨。凭证就是那几十到几百字节,省不了也不该省。

追问 3登录成功了,收藏还提示未登录,请求里也有 Token,从哪查?
参考回答

先确认这个 Token 是不是这次登录返回的那个,别是缓存里的旧值;再看服务端收藏接口有没有挂认证中间件、读的头名字对不对。

追问 4账号密码也是凭证,为什么不每次请求都带账号密码?
参考回答

每个请求都带密码,泄露面太大,服务端每次还要做慢哈希比对。所以只在登录时用一次密码,换一个短期凭证用后续请求。

# 什么是 Cookie

← Session 与 TokenSocket →

fe