本文介绍接口自动化里最常见的三种鉴权写法,并结合本框架说明怎么用。


先搞懂:什么是鉴权?

想象你去公司上班:

  • 没带工牌:保安不让进 → 接口返回 401/403(未授权)
  • 带了工牌:保安看一眼就让进 → 接口正常返回数据(已授权)

API 鉴权,就是服务器先确认「你是谁」,再决定能不能访问这个接口。


行业里常见吗?三种方式分别是什么?

在 Postman、JMeter、HttpRunner、pytest 等工具/框架里,自动化鉴权几乎都绕不开下面这件事:

先拿到凭证(Token / Cookie / Session)→ 存起来 → 后面的请求带上它

做法 行业里叫什么 常见程度
方式一:框架自动注入 Token 前置登录 + 统一鉴权头 / Auth Hook ⭐⭐⭐ 很常见
方式二:用 ${变量} 手动引用 参数关联 / 变量替换 ⭐⭐⭐ 很常见
方式三:pytest Fixture 前置登录 setup / session fixture ⭐⭐⭐ pytest 项目里很常见

补充说明:

  • 真实项目里还有 API Key、OAuth2、Basic Auth、Cookie-Session 等,但自动化脚本里「登录拿 Token,再带给后续接口」仍是最主流的一类。
  • 方式一和方式二经常同时存在:默认用方式一省事,特殊用例用方式二精细控制。
  • 方式三适合纯 Python 用例;YAML 数据驱动的项目优先用方式一。

无论哪种方式,核心都是三步

① 登录(或调用鉴权接口)拿到 Token
        ↓
② 存到「公共仓库」( Context,同时写内存和 extract.yaml)
        ↓
③ 后续请求带上 Token(框架自动塞,或 YAML 里写 ${auth_token})

下面分别说明三种做法。


方式一:Token 自动注入⭐

一句话理解

登录用例把 Token 存进仓库;后面只要在 YAML 里写 need_auth: true,发请求时框架自动把 Token 放进请求头——像游乐园「进门刷一次票,每个项目不用再单独买票」。

原理

登录 YAML(extract)→ Context 保存 Token → 业务 YAML(need_auth: true)→ RequestHandler 自动注入请求头

本框架完整流程(一次 pytest 运行)

pytest 启动
    ↓
conftest:清空 config/extract.yaml(避免上次残留的 Token 干扰本次)← 注意:不是「下次运行接着用」
    ↓
扫描 data 下所有 *_test.yaml,按路径+文件名排序(如 01_login 会排在 02_xxx 前面)
    ↓
┌─ 登录用例 ─────────────────────────────────────────┐
│  POST /api/example/login                       │
│  extract:                                         │
│    auth_token: "data.auth"   ← 从响应里抠出 Token │
└───────────────────────────────────────────────────┘
    ↓
响应 code=0 时 → Context.set("auth_token", "abc123")  (内存 + extract.yaml)
    ↓
┌─ 业务用例 ─────────────────────────────────────────┐
│  need_auth: true   ← 告诉框架:这接口要带 Token   │
│  POST /api/example/get_list                     │
└───────────────────────────────────────────────────┘
    ↓
RequestHandler.send():
  token = Context.get("auth_token")
  headers 里没有 auth 时 → 自动补上 auth 和 Authorization: Bearer xxx
  (若 YAML 里已经写了 auth,则不会覆盖,方便测「无效 Token」)

YAML 示例

1. 登录并提取 Token

-
  title: "登录成功"
  base_url_key: "base_url"
  request:
    method: "POST"
    url: "/api/example/login"
    headers:
      Content-Type: "application/x-www-form-urlencoded"
    data:
      phoneCode: "86"
      phoneNo: "13800138000"
      captcha: "1234"
  extract:
    auth_token: "data.auth"
  validate:
    - eq: ["status_code", 200]
    - eq: ["json.code", 0]

2. 业务接口:只加 need_auth

-
  title: "查询课程列表"
  base_url_key: "base_url"
  request:
    method: "POST"
    url: "/api/example/get_list"
    need_auth: true
    headers:
      Content-Type: "application/x-www-form-urlencoded"
    data:
      currentPage: 1
      perPage: 10
  validate:
    - eq: ["status_code", 200]
    - eq: ["json.code", 0]

和代码的对应关系

步骤 文件 做什么
每次运行清空旧 Token conftest.py Context.clear_extract_file()
用例排序、变量替换、提取 test_api.py replace_varssendextract_and_set
自动注入 Token request_handler.py need_auth 为 true 时 Context.get("auth_token")
存/取变量 common/utils.py Context.set / get / extract_and_set

提取 Token 时有个细节:只有响应里 code == 0 才会写入 Context,登录失败不会误存旧 Token。

Context 是干什么的?

可以把它想成本次测试运行的公共储物柜

方法 存哪 作用
Context.set(key, val) 内存 + config/extract.yaml 保存变量,方便调试时打开文件看
Context.get(key) 优先内存 取变量给注入或替换用
Context.replace_vars(data) 不存 把字符串里的 ${auth_token} 换成真实值

关于 extract.yaml 的常见误解:

  • 同一次 pytest 运行里,前面用例存的 Token,后面用例能用。
  • 不是「下次跑测试不用登录」——每次启动 pytest 都会先清空该文件。

优点

  • ✅ 业务用例只写 need_auth: true,不用每个接口重复写 Token
  • ✅ 全 YAML 配置,改接口不用改 Python
  • ✅ 和方式二共用同一套 Context,随时可切换手动引用

缺点

  • ❌ 必须有一份「登录」YAML,且排序上要先于依赖 Token 的用例
  • ❌ 不同项目鉴权头名字不一样时,要在 RequestHandler 里统一适配(本框架默认补 authAuthorization

方式二:在 YAML 里用 ${变量名} 手动引用

一句话理解

Token 还是登录时 extract 进 Context,但need_auth,而是在 headers / data / params 里自己写 ${auth_token}——像「不刷通用年卡,每个项目单独出示门票」。

和方式一的区别

方式一 方式二
谁把 Token 放进请求 框架(need_auth: true 你自己在 YAML 里写 ${auth_token}
典型场景 大部分正常业务接口 测无效 Token、Token 放 body、Cookie 等特殊格式

YAML 示例

登录(与方式一相同)

  extract:
    auth_token: "data.auth"

业务接口:手动引用

-
  title: "查询课程列表"
  base_url_key: "base_url"
  request:
    method: "POST"
    url: "/api/example/get_list"
    headers:
      Content-Type: "application/x-www-form-urlencoded"
      auth: "${auth_token}"
    data:
      currentPage: 1
      perPage: 10

测无效 Token(方式二更合适)

    headers:
      auth: "invalid-token-12345"

执行流程

登录 extract → Context 有 auth_token
    ↓
发请求前:对 headers / data / params / json 做 replace_vars
    ↓
"${auth_token}" 变成真实字符串 → 发出请求

框架会对 headersdataparamsjson 都做替换,不只 data

优点

  • ✅ 灵活:Token 可放 header、body、Cookie 任意字段
  • ✅ 方便写负向用例(故意写错 Token)
  • ✅ 不依赖 need_auth 开关

缺点

  • ❌ 每个要鉴权的用例都要手写 ${auth_token},容易漏写
  • ❌ 鉴权头字段名不统一时,维护量比方式一大

方式三:pytest Fixture 前置登录

一句话理解

不(或不仅)在 YAML 里写登录,而是在 conftest.py 里用 pytest 的 Fixture 在测试开始前先登录——像「进园区前保安统一发工牌,再开始参观」。

和方式一的区别

对比项 方式一(YAML 登录) 方式三(Fixture 登录)
登录写在哪 YAML 用例 conftest.py 的 Fixture
登录何时执行 跑到登录那条 YAML 时 Fixture 的 scope 决定(常见 session = 整场只登一次)
Token 存哪 Context(同方式一) Context(同方式一)
后续怎么带 Token need_auth${auth_token} 一样,本框架的 RequestHandler 不用改
更适合 YAML 数据驱动 纯 pytest 函数用例

说明:方式三不是和方式一对立的另一套注入机制,只是「登录动作」从 YAML 挪到了 Fixture;带 Token 仍可用 need_auth 或方式二。

示例代码

conftest.py:会话级自动登录

import pytest
from common.request_handler import RequestHandler
from common.utils import Context

@pytest.fixture(scope="session", autouse=True)
def auto_login():
    resp = RequestHandler.send(
        method="POST",
        url="https://api.example.com/api/account/login",
        headers={"Content-Type": "application/x-www-form-urlencoded"},
        data={"phoneCode": "86", "phoneNo": "13800138000", "captcha": "1234"},
    )
    if resp and resp.json().get("code") == 0:
        Context.set("auth_token", resp.json()["data"]["auth"])
    yield

测试用例:照常 need_auth

def test_query_course():
    resp = RequestHandler.send(
        method="POST",
        url="https://api.example.com/api/v1/course/get_list",
        need_auth=True,
        headers={"Content-Type": "application/x-www-form-urlencoded"},
        data={"currentPage": 1, "perPage": 10},
    )
    assert resp.json()["code"] == 0

Fixture 两个常用参数

scope:登录执行几次

含义
function 每个测试函数前各登一次
module 每个 .py 文件登一次
session 整场 pytest 只登一次(最常用)

autouse:要不要每个测试都自动跑

含义
False(默认) 只有测试函数参数里写了该 fixture 名才执行
True 所有测试自动先执行该 fixture

优点

  • ✅ pytest 官方惯用写法,生命周期清晰(登录 / 建库 / 清数据都能放 fixture)
  • ✅ 登录逻辑集中在 Python,适合复杂鉴权(加密、多步 OAuth)

缺点

  • ❌ 要多写 Python,和「全 YAML 驱动」风格不太搭
  • autouse=True + session 时,不需要登录的用例也会先登一次(可用 autouse=False 按需引用避免)

附录:装饰器方式(了解即可,pytest 项目一般不首选)

有些教程会用 @login_required 这种装饰器在每个测试函数执行前调登录。它和 Fixture 的区别:

装饰器 pytest Fixture
本质 包一层新函数 独立的前置/后置钩子
全局自动执行 要自己写 autouse 或逐个加装饰器 autouse=True 原生支持
在 pytest 里 能用,但不如 Fixture 直观 推荐

常见误区:

@pytest.mark.login_required  # ❌ 只是打标签,不会自动登录
@login_required              # ✅ 装饰器写法才会包一层 wrapper
def test_get_user():
    pass

接口自动化里更常见的是方式一 / 二 / 三;装饰器多见于 Web 接口开发(如 Flask),测试项目里知道原理即可。


三种方式对比(一张表看完)

方式 怎么触发登录 Token 放哪 怎么带给后续接口 最适合
一:自动注入 YAML 登录用例 Context need_auth: true ⭐ YAML 驱动
二:变量引用 YAML 登录用例 Context ${auth_token} 写在 YAML 特殊鉴权、负向用例
三:Fixture conftest Fixture Context 同左两种均可 纯 pytest 代码用例

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐