4. Mock Token 端点实现:模拟 /oauth/token 接口,返回固定格式的 Access Token 与 Refresh Token
在依赖隔离调试中,真实授权服务器(AS)往往不可用或响应不稳定。通过 Mock 一个 /oauth/token 端点,我们可以让被测系统(SUT)在完全可控的 Token 响应下运行,从而聚焦于业务逻辑与 Token 生命周期管理。
4.1 Mock 端点核心职责
Mock Token 端点需要模拟授权服务器在 Client Credentials 与 Authorization Code 两种最常用流程下的 Token 颁发行为。其核心职责包括:
- 请求验证:检查
grant_type、client_id、client_secret等必填参数。 - 固定响应:返回预定义的 Access Token、Refresh Token、Token 类型及过期时间。
- 状态模拟:支持模拟成功响应、参数错误、客户端认证失败等场景。
关键原则:Mock 端点不执行真实签名或加密,仅返回符合 OAuth2.0 规范结构的静态 Token 字符串,便于调试时人工识别与断言。
4.2 接口规范与参数清单
下表列出了 Mock /oauth/token 端点支持的请求参数与固定响应字段:
| 方向 | 参数 / 字段 | 类型 | 说明 |
|---|---|---|---|
| 请求 | grant_type |
string | 固定为 client_credentials 或 authorization_code |
client_id |
string | 预置客户端标识,如 mock-client |
|
client_secret |
string | 预置客户端密钥,如 mock-secret |
|
code |
string | 仅 authorization_code 时需要,固定为 mock-auth-code |
|
| 响应 | access_token |
string | 固定值 mock-access-token-v1 |
token_type |
string | 固定为 Bearer |
|
expires_in |
int | 固定为 3600(1 小时) |
|
refresh_token |
string | 固定值 mock-refresh-token-v1 |
|
scope |
string | 固定为 read write |
4.3 Mock 端点处理流程
下图展示了 Mock Token 端点的内部处理逻辑与状态分支:
4.4 代码实现示例(Node.js + Express)
以下是一个轻量级 Mock Token 端点的实现,使用 Express 框架,支持两种 grant_type 并返回固定 Token:
const express = require('express');
const app = express();
app.use(express.json());
const MOCK_CLIENTS = {
'mock-client': { secret: 'mock-secret', grants: ['client_credentials', 'authorization_code'] }
};
const MOCK_TOKENS = {
access_token: 'mock-access-token-v1',
token_type: 'Bearer',
expires_in: 3600,
refresh_token: 'mock-refresh-token-v1',
scope: 'read write'
};
app.post('/oauth/token', (req, res) => {
const { grant_type, client_id, client_secret, code } = req.body;
// 1. 参数完整性校验
if (!grant_type || !client_id || !client_secret) {
return res.status(400).json({ error: 'invalid_request', error_description: 'Missing required parameters' });
}
// 2. 客户端认证
const client = MOCK_CLIENTS[client_id];
if (!client || client.secret !== client_secret) {
return res.status(401).json({ error: 'invalid_client', error_description: 'Client authentication failed' });
}
// 3. grant_type 分支处理
if (grant_type === 'client_credentials') {
return res.status(200).json(MOCK_TOKENS);
}
if (grant_type === 'authorization_code') {
if (code !== 'mock-auth-code') {
return res.status(400).json({ error: 'invalid_grant', error_description: 'Invalid authorization code' });
}
return res.status(200).json(MOCK_TOKENS);
}
// 4. 不支持的 grant_type
return res.status(400).json({ error: 'unsupported_grant_type', error_description: 'Grant type not supported' });
});
app.listen(4000, () => console.log('Mock OAuth2 Token endpoint running on port 4000'));
4.5 测试验证与调试技巧
启动 Mock 服务后,可以使用 curl 快速验证端点行为:
# 测试 Client Credentials 流程
curl -X POST http://localhost:4000/oauth/token \
-H "Content-Type: application/json" \
-d '{"grant_type":"client_credentials","client_id":"mock-client","client_secret":"mock-secret"}'
# 测试 Authorization Code 流程
curl -X POST http://localhost:4000/oauth/token \
-H "Content-Type: application/json" \
-d '{"grant_type":"authorization_code","client_id":"mock-client","client_secret":"mock-secret","code":"mock-auth-code"}'
# 测试错误场景:无效客户端
curl -X POST http://localhost:4000/oauth/token \
-H "Content-Type: application/json" \
-d '{"grant_type":"client_credentials","client_id":"invalid","client_secret":"wrong"}'
调试建议:在集成测试中,将 SUT 的 Token 端点 URL 替换为
http://localhost:4000/oauth/token,即可在不依赖真实授权服务器的情况下,验证 Token 获取、缓存、刷新及过期处理逻辑。
4.6 常见 Mock 场景对照
| 测试场景 | 触发条件 | 预期响应 | 调试目标 |
|---|---|---|---|
| 正常 Token 获取 | 合法 client_id + secret | 200 + 固定 Token JSON | 验证 SUT 正确解析 Token 字段 |
| 客户端认证失败 | 错误 client_secret | 401 + invalid_client | 验证 SUT 错误处理与重试逻辑 |
| 无效授权码 | authorization_code + 错误 code | 400 + invalid_grant | 验证 SUT 授权码校验分支 |
| 不支持的 grant_type | grant_type = password | 400 + unsupported_grant_type | 验证 SUT 是否过滤非法流程 |
注意:Mock 端点返回的 Token 不具备真实签名,切勿在生产环境或安全测试中使用。本 Mock 仅用于依赖隔离调试,确保 SUT 在可控输入下正确运行。