优化测试verifyToken接口脚本
This commit is contained in:
@@ -34,7 +34,7 @@ AGENT_AUTH_JWT_SECRET=
|
|||||||
PLAYX_SESSION_EXPIRE_SECONDS=3600
|
PLAYX_SESSION_EXPIRE_SECONDS=3600
|
||||||
# verifyToken 是否仅本地联调(false=走对方远程校验)
|
# verifyToken 是否仅本地联调(false=走对方远程校验)
|
||||||
PLAYX_VERIFY_TOKEN_LOCAL_ONLY=false
|
PLAYX_VERIFY_TOKEN_LOCAL_ONLY=false
|
||||||
# verifyToken:完整 https URL 时 Body 仅 request_id+token、签名明文同式;相对路径时拼基址+商户四字段
|
# verifyToken:完整 https URL 时 Body merchant_code+request_id+token、签名明文同序;相对路径时拼基址+商户四字段
|
||||||
PLAYX_TOKEN_VERIFY_URL=https://callback-mallsys.superior3.net/callback/api/mallsys/plx/auth/verify-token
|
PLAYX_TOKEN_VERIFY_URL=https://callback-mallsys.superior3.net/callback/api/mallsys/plx/auth/verify-token
|
||||||
# verifyToken 仅本地联调时的默认用户ID
|
# verifyToken 仅本地联调时的默认用户ID
|
||||||
PLAYX_VERIFY_TOKEN_LOCAL_DEFAULT_USER_ID=testmyr
|
PLAYX_VERIFY_TOKEN_LOCAL_DEFAULT_USER_ID=testmyr
|
||||||
|
|||||||
@@ -443,13 +443,16 @@ class Playx extends Api
|
|||||||
$client = new \GuzzleHttp\Client($clientOptions);
|
$client = new \GuzzleHttp\Client($clientOptions);
|
||||||
|
|
||||||
if ($isAbsoluteVerifyUrl) {
|
if ($isAbsoluteVerifyUrl) {
|
||||||
|
$merchantCode = strval(config('playx.angpow_import.merchant_code', ''));
|
||||||
$authKey = strval(config('playx.angpow_import.auth_key', ''));
|
$authKey = strval(config('playx.angpow_import.auth_key', ''));
|
||||||
if ($authKey === '') {
|
if ($merchantCode === '' || $authKey === '') {
|
||||||
return $this->error(__('PlayX API not configured'));
|
return $this->error(__('PlayX API not configured'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// PlayX 文档:Body 仅 request_id + token。X-Request-Signature 与 angpow-imports 同源算法(HMAC-SHA1→Base64、密钥解析同 angpow),明文与 Body 字段一致。
|
// 回调网关要求 Body 含 merchant_code;签名字符串与参与签名的字段顺序与 angpow 风格一致(HMAC-SHA1→Base64、密钥解析同 angpow)。
|
||||||
$signatureInput = 'request_id=' . $requestId . '&token=' . $token;
|
$signatureInput = 'merchant_code=' . $merchantCode
|
||||||
|
. '&request_id=' . $requestId
|
||||||
|
. '&token=' . $token;
|
||||||
$signature = $this->buildPlayxTokenVerifySignature($signatureInput, $authKey);
|
$signature = $this->buildPlayxTokenVerifySignature($signatureInput, $authKey);
|
||||||
if ($signature === null) {
|
if ($signature === null) {
|
||||||
return $this->error(__('Invalid signature'), null, 0, ['statusCode' => 500]);
|
return $this->error(__('Invalid signature'), null, 0, ['statusCode' => 500]);
|
||||||
@@ -460,8 +463,9 @@ class Playx extends Api
|
|||||||
'X-Request-Signature' => $signature,
|
'X-Request-Signature' => $signature,
|
||||||
];
|
];
|
||||||
$payload = [
|
$payload = [
|
||||||
'request_id' => $requestId,
|
'merchant_code' => $merchantCode,
|
||||||
'token' => $token,
|
'request_id' => $requestId,
|
||||||
|
'token' => $token,
|
||||||
];
|
];
|
||||||
$res = $client->post($targetVerifyUrl, [
|
$res = $client->post($targetVerifyUrl, [
|
||||||
'headers' => $headers,
|
'headers' => $headers,
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ return [
|
|||||||
'api' => [
|
'api' => [
|
||||||
'base_url' => strval(env('PLAYX_API_BASE_URL', '')),
|
'base_url' => strval(env('PLAYX_API_BASE_URL', '')),
|
||||||
'secret_key' => strval(env('PLAYX_API_SECRET_KEY', '')),
|
'secret_key' => strval(env('PLAYX_API_SECRET_KEY', '')),
|
||||||
// 完整 https URL:回调 Body 仅 request_id+token,签名 request_id&token(HMAC 同 angpow);相对路径:拼基址 + 商户体
|
// 完整 https URL:回调 Body merchant_code+request_id+token,签名同字段拼接(HMAC 同 angpow);相对路径:拼基址 + 商户体
|
||||||
'token_verify_url' => strval(env('PLAYX_TOKEN_VERIFY_URL', '/api/v1/auth/verify-token')),
|
'token_verify_url' => strval(env('PLAYX_TOKEN_VERIFY_URL', '/api/v1/auth/verify-token')),
|
||||||
'bonus_grant_url' => '/api/v1/bonus/grant',
|
'bonus_grant_url' => '/api/v1/bonus/grant',
|
||||||
'balance_credit_url' => '/api/v1/balance/credit',
|
'balance_credit_url' => '/api/v1/balance/credit',
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ flowchart LR
|
|||||||
2. playX 前端通过 postMessage 将 **playX 下发的 token**(及必要上下文)传给商城 H5。
|
2. playX 前端通过 postMessage 将 **playX 下发的 token**(及必要上下文)传给商城 H5。
|
||||||
3. 商城 H5 调用商城后端 **`POST /api/v1/mall/verifyToken`**(前端只传 `token`),由商城后端向 **Token Verification API** 发起校验。
|
3. 商城 H5 调用商城后端 **`POST /api/v1/mall/verifyToken`**(前端只传 `token`),由商城后端向 **Token Verification API** 发起校验。
|
||||||
4. **前提**:配置 **`playX.verify_token_local_only = false`**,且 **`PLAYX_TOKEN_VERIFY_URL`** 已配置:
|
4. **前提**:配置 **`playX.verify_token_local_only = false`**,且 **`PLAYX_TOKEN_VERIFY_URL`** 已配置:
|
||||||
- **完整 `https://...` URL**(如回调):商城 `POST` 该地址;JSON Body **仅** PlayX 文档约定的 **`request_id`、`token`**;**`X-Request-Signature`** 与 angpow-imports **同源算法**(密钥 **`PLAYX_ANGPOW_IMPORT_AUTH_KEY`**),签名字符串为 **`request_id={id}&token={token}`**;无需 `PLAYX_ANGPOW_MERCHANT_CODE`、无需 `PLAYX_ANGPOW_IMPORT_BASE_URL`。
|
- **完整 `https://...` URL**(如回调):商城 `POST` 该地址;JSON Body 含 **`merchant_code`**(`PLAYX_ANGPOW_MERCHANT_CODE`)、**`request_id`、`token`**;**`X-Request-Signature`** 与 angpow-imports **同源算法**(密钥 **`PLAYX_ANGPOW_IMPORT_AUTH_KEY`**),签名字符串为 **`merchant_code=...&request_id=...&token=...`**;无需 `PLAYX_ANGPOW_IMPORT_BASE_URL`。
|
||||||
- **相对路径**(如 `/api/v1/auth/verify-token`):需同时配置 **`PLAYX_ANGPOW_IMPORT_BASE_URL`**,Body 使用 **`request_date`**,并按商户约定附带签名等。
|
- **相对路径**(如 `/api/v1/auth/verify-token`):需同时配置 **`PLAYX_ANGPOW_IMPORT_BASE_URL`**,Body 使用 **`request_date`**,并按商户约定附带签名等。
|
||||||
5. playX 返回 **`user_id`、`username`**(及可选会话过期时间等)。
|
5. playX 返回 **`user_id`、`username`**(及可选会话过期时间等)。
|
||||||
6. 商城写入 **`mall_playx_session`**(`session_id` + 上述 `user_id`/`username` + 过期时间),后续 H5 可用 **`session_id`** 或 **`token`(商城临时 token,见模式 B)** 调用资产/领取等接口。
|
6. 商城写入 **`mall_playx_session`**(`session_id` + 上述 `user_id`/`username` + 过期时间),后续 H5 可用 **`session_id`** 或 **`token`(商城临时 token,见模式 B)** 调用资产/领取等接口。
|
||||||
@@ -81,7 +81,7 @@ flowchart LR
|
|||||||
幂等与安全:
|
幂等与安全:
|
||||||
|
|
||||||
- H5 **不要**把 playX 的 `user_id` 当作唯一可信凭据直传下单;**以 token 换 session** 或由商城签发 token 的流程为准。
|
- H5 **不要**把 playX 的 `user_id` 当作唯一可信凭据直传下单;**以 token 换 session** 或由商城签发 token 的流程为准。
|
||||||
- 若 `PLAYX_TOKEN_VERIFY_URL` 为**完整 https URL**:Body 仅 **`request_id`、`token`**(与 PlayX 文档一致);`X-Request-Signature` 为 angpow 同源 HMAC,明文 **`request_id=...&token=...`**;H5 不参与签名。
|
- 若 `PLAYX_TOKEN_VERIFY_URL` 为**完整 https URL**:Body 含 **`merchant_code`、`request_id`、`token`**(回调网关必填 `merchant_code`);`X-Request-Signature` 为 angpow 同源 HMAC,明文 **`merchant_code=...&request_id=...&token=...`**;H5 不参与签名。
|
||||||
- 若为**相对路径 + 基地址**商户网关:鉴权/签名由商城后端完成(`merchant_code/request_date/request_id` + `X-Request-Signature` 等);H5 不参与签名计算。
|
- 若为**相对路径 + 基地址**商户网关:鉴权/签名由商城后端完成(`merchant_code/request_date/request_id` + `X-Request-Signature` 等);H5 不参与签名计算。
|
||||||
|
|
||||||
#### 4.1.3 模式 B:本地 / 无 playX 环境(商城自校验,不请求 playX)
|
#### 4.1.3 模式 B:本地 / 无 playX 环境(商城自校验,不请求 playX)
|
||||||
@@ -223,11 +223,12 @@ flowchart LR
|
|||||||
- **完整 URL**:由环境变量 **`PLAYX_TOKEN_VERIFY_URL`** 填完整地址,例如:
|
- **完整 URL**:由环境变量 **`PLAYX_TOKEN_VERIFY_URL`** 填完整地址,例如:
|
||||||
`https://callback-mallsys.superior3.net/callback/api/mallsys/plx/auth/verify-token`
|
`https://callback-mallsys.superior3.net/callback/api/mallsys/plx/auth/verify-token`
|
||||||
- **请求 Header**:与 **angpow-imports** 相同风格,仅 **`Content-Type: application/json`**、**`X-Request-Signature`**(`Base64(HMAC-SHA1(canonical, PLAYX_ANGPOW_IMPORT_AUTH_KEY))`,密钥解析与 angpow 一致:hex / base64 / 明文)。
|
- **请求 Header**:与 **angpow-imports** 相同风格,仅 **`Content-Type: application/json`**、**`X-Request-Signature`**(`Base64(HMAC-SHA1(canonical, PLAYX_ANGPOW_IMPORT_AUTH_KEY))`,密钥解析与 angpow 一致:hex / base64 / 明文)。
|
||||||
- **签名明文 canonical**:`request_id={request_id}&token={token}`(与 JSON Body 字段一致,无 `merchant_code` / `request_date`)。
|
- **签名明文 canonical**:`merchant_code={merchant_code}&request_id={request_id}&token={token}`(与 JSON Body 参与签名字段一致)。
|
||||||
- **请求 Body**(与 PlayX 平台 Token 校验文档一致):
|
- **请求 Body**(回调网关实际校验;在 PlayX 文档 `request_id`+`token` 基础上增加对端要求的 **`merchant_code`**):
|
||||||
|
|
||||||
| 字段名 | 类型 | 必填 | 说明 |
|
| 字段名 | 类型 | 必填 | 说明 |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
|
| `merchant_code` | String | 是 | 与 `PLAYX_ANGPOW_MERCHANT_CODE` 一致。 |
|
||||||
| `request_id` | String | 是 | 商城生成的请求追踪号。 |
|
| `request_id` | String | 是 | 商城生成的请求追踪号。 |
|
||||||
| `token` | String | 是 | 前端传入的 playX 临时凭证。 |
|
| `token` | String | 是 | 前端传入的 playX 临时凭证。 |
|
||||||
|
|
||||||
@@ -235,6 +236,7 @@ flowchart LR
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
"merchant_code": "plx",
|
||||||
"request_id": "mall_20260319_9f1b6d",
|
"request_id": "mall_20260319_9f1b6d",
|
||||||
"token": "eyJhbGciOi..."
|
"token": "eyJhbGciOi..."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -272,7 +272,7 @@ curl -G 'http://localhost:1818/api/v1/temLogin' --data-urlencode 'username=demo_
|
|||||||
* 仅接受商城临时登录 token(类型 **`muser`**),校验 `token` 表后写入 **`mall_session`**。
|
* 仅接受商城临时登录 token(类型 **`muser`**),校验 `token` 表后写入 **`mall_session`**。
|
||||||
* 返回的 `data.user_id` 为 **`playx_user_id`**(与资产表一致)。
|
* 返回的 `data.user_id` 为 **`playx_user_id`**(与资产表一致)。
|
||||||
* **`verify_token_local_only = false`**(生产对接 playX)
|
* **`verify_token_local_only = false`**(生产对接 playX)
|
||||||
* 需配置 **`PLAYX_TOKEN_VERIFY_URL`**(完整 `https` 回调或相对路径)及 **`PLAYX_ANGPOW_IMPORT_AUTH_KEY`** 等(见 `docs/PlayX-对接文档(积分商城).md` §5.2)。
|
* 需配置 **`PLAYX_TOKEN_VERIFY_URL`**(完整 `https` 回调或相对路径)、**`PLAYX_ANGPOW_MERCHANT_CODE`**、**`PLAYX_ANGPOW_IMPORT_AUTH_KEY`** 等(见 `docs/PlayX-对接文档(积分商城).md` §5.2)。
|
||||||
* 相对路径时尚需 **`PLAYX_ANGPOW_IMPORT_BASE_URL`**;未配置则返回未配置类错误。
|
* 相对路径时尚需 **`PLAYX_ANGPOW_IMPORT_BASE_URL`**;未配置则返回未配置类错误。
|
||||||
|
|
||||||
#### 请求参数
|
#### 请求参数
|
||||||
|
|||||||
@@ -304,7 +304,7 @@ curl -X POST 'https://{商城域名}/api/v1/mall/dailyPush' \
|
|||||||
**前端入参约定(重要)**:
|
**前端入参约定(重要)**:
|
||||||
- 调用本接口时 **仅需 `token`**(或兼容 `session`);**不要**传 `request_id` / `request_date` / 商户字段(均由商城后端生成后请求上游)。
|
- 调用本接口时 **仅需 `token`**(或兼容 `session`);**不要**传 `request_id` / `request_date` / 商户字段(均由商城后端生成后请求上游)。
|
||||||
- 建议 **`Content-Type: application/json`**,Body:`{"token":"..."}`。若使用 **form-data**(如图二),请同样只传 `token`(及可选 `lang`);避免缺少 `token` 键名。
|
- 建议 **`Content-Type: application/json`**,Body:`{"token":"..."}`。若使用 **form-data**(如图二),请同样只传 `token`(及可选 `lang`);避免缺少 `token` 键名。
|
||||||
- 商城请求上游回调地址时:Body **仅** **`request_id`、`token`**(与 PlayX 文档一致);`X-Request-Signature` 与 angpow-imports **同源算法**,canonical 为 **`request_id=...&token=...`**。
|
- 商城请求上游回调地址时:Body 含 **`merchant_code`、`request_id`、`token`**(对端必填 `merchant_code`);`X-Request-Signature` 与 angpow-imports **同源算法**,canonical 为 **`merchant_code=...&request_id=...&token=...`**。
|
||||||
|
|
||||||
**请求示例:**
|
**请求示例:**
|
||||||
```json
|
```json
|
||||||
@@ -644,8 +644,8 @@ GET /api/v1/mall/addressList?session_id=fc7f3e3f0d0f4cb29f66e4c8fbab4f66
|
|||||||
| `PLAYX_DAILY_PUSH_SECRET` | 非空则 Daily Push 必须带合法 HMAC 头 |
|
| `PLAYX_DAILY_PUSH_SECRET` | 非空则 Daily Push 必须带合法 HMAC 头 |
|
||||||
| `PLAYX_VERIFY_TOKEN_LOCAL_ONLY` | 为 true 时 verifyToken 不请求 playX 远程 |
|
| `PLAYX_VERIFY_TOKEN_LOCAL_ONLY` | 为 true 时 verifyToken 不请求 playX 远程 |
|
||||||
| `PLAYX_ANGPOW_IMPORT_BASE_URL` | Angpow 推送等接口基地址;**相对路径** `verify-token` 时亦作其基地址 |
|
| `PLAYX_ANGPOW_IMPORT_BASE_URL` | Angpow 推送等接口基地址;**相对路径** `verify-token` 时亦作其基地址 |
|
||||||
| `PLAYX_TOKEN_VERIFY_URL` | **完整 `https://` URL**:回调 Body 仅 `request_id`+`token`,签名明文同字段;**相对路径**:拼基地址 + 商户四字段 |
|
| `PLAYX_TOKEN_VERIFY_URL` | **完整 `https://` URL**:回调 Body `merchant_code`+`request_id`+`token`,签名明文同序;**相对路径**:拼基地址 + 商户四字段 |
|
||||||
| `PLAYX_ANGPOW_MERCHANT_CODE` | 仅 **相对路径** `verify-token` 需要 |
|
| `PLAYX_ANGPOW_MERCHANT_CODE` | **回调与相对路径** `verify-token` 均需 |
|
||||||
| `PLAYX_ANGPOW_IMPORT_AUTH_KEY` | 回调与相对路径的 HMAC 密钥(与 angpow-imports 相同) |
|
| `PLAYX_ANGPOW_IMPORT_AUTH_KEY` | 回调与相对路径的 HMAC 密钥(与 angpow-imports 相同) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ declare(strict_types=1);
|
|||||||
*
|
*
|
||||||
* 可选环境变量(未设置则从项目根 .env 读取):
|
* 可选环境变量(未设置则从项目根 .env 读取):
|
||||||
* PLAYX_TOKEN_VERIFY_URL 默认 https://callback-mallsys.superior3.net/callback/api/mallsys/plx/auth/verify-token
|
* PLAYX_TOKEN_VERIFY_URL 默认 https://callback-mallsys.superior3.net/callback/api/mallsys/plx/auth/verify-token
|
||||||
|
* PLAYX_ANGPOW_MERCHANT_CODE 回调 Body merchant_code(必填)
|
||||||
* PLAYX_ANGPOW_IMPORT_AUTH_KEY 与 angpow-imports 相同的 HMAC 密钥
|
* PLAYX_ANGPOW_IMPORT_AUTH_KEY 与 angpow-imports 相同的 HMAC 密钥
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -75,19 +76,25 @@ if ($url === '') {
|
|||||||
$url = 'https://callback-mallsys.superior3.net/callback/api/mallsys/plx/auth/verify-token';
|
$url = 'https://callback-mallsys.superior3.net/callback/api/mallsys/plx/auth/verify-token';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$merchantCode = strval($_ENV['PLAYX_ANGPOW_MERCHANT_CODE'] ?? getenv('PLAYX_ANGPOW_MERCHANT_CODE') ?: '');
|
||||||
$authKey = strval($_ENV['PLAYX_ANGPOW_IMPORT_AUTH_KEY'] ?? getenv('PLAYX_ANGPOW_IMPORT_AUTH_KEY') ?: '');
|
$authKey = strval($_ENV['PLAYX_ANGPOW_IMPORT_AUTH_KEY'] ?? getenv('PLAYX_ANGPOW_IMPORT_AUTH_KEY') ?: '');
|
||||||
|
if ($merchantCode === '') {
|
||||||
|
fwrite(STDERR, "缺少 PLAYX_ANGPOW_MERCHANT_CODE(请在 .env 配置或导出环境变量)\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
if ($authKey === '') {
|
if ($authKey === '') {
|
||||||
fwrite(STDERR, "缺少 PLAYX_ANGPOW_IMPORT_AUTH_KEY(请在 .env 配置或导出环境变量)\n");
|
fwrite(STDERR, "缺少 PLAYX_ANGPOW_IMPORT_AUTH_KEY(请在 .env 配置或导出环境变量)\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
$requestId = 'mall_cli_' . uniqid();
|
$requestId = 'mall_cli_' . uniqid();
|
||||||
$canonical = 'request_id=' . $requestId . '&token=' . $token;
|
$canonical = 'merchant_code=' . $merchantCode . '&request_id=' . $requestId . '&token=' . $token;
|
||||||
$signature = buildSignature($canonical, $authKey);
|
$signature = buildSignature($canonical, $authKey);
|
||||||
|
|
||||||
$payload = json_encode([
|
$payload = json_encode([
|
||||||
'request_id' => $requestId,
|
'merchant_code' => $merchantCode,
|
||||||
'token' => $token,
|
'request_id' => $requestId,
|
||||||
|
'token' => $token,
|
||||||
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||||
if ($payload === false) {
|
if ($payload === false) {
|
||||||
fwrite(STDERR, "JSON 编码失败\n");
|
fwrite(STDERR, "JSON 编码失败\n");
|
||||||
|
|||||||
Reference in New Issue
Block a user