优化Token验证接口

This commit is contained in:
2026-05-06 10:25:56 +08:00
parent 04680408e6
commit 438580d72c
5 changed files with 17 additions and 26 deletions

View File

@@ -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 时签名同 angpowBody request_id/request_date/token;相对路径时拼基址+商户四字段 # verifyToken完整 https URL 时 Body 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

View File

@@ -443,18 +443,13 @@ 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 ($merchantCode === '' || $authKey === '') { if ($authKey === '') {
return $this->error(__('PlayX API not configured')); return $this->error(__('PlayX API not configured'));
} }
// 与 angpow-imports 同源HMAC-SHA1Base64;仅 X-Request-SignatureBody 对齐对端必填 request_date + PlayX 文档 request_id/token // PlayX 文档Body 仅 request_id + token。X-Request-Signature 与 angpow-imports 同源算法(HMAC-SHA1Base64、密钥解析同 angpow明文与 Body 字段一致。
$requestDate = strval(time()); $signatureInput = 'request_id=' . $requestId . '&token=' . $token;
$signatureInput = 'merchant_code=' . $merchantCode
. '&request_date=' . $requestDate
. '&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]);
@@ -466,7 +461,6 @@ class Playx extends Api
]; ];
$payload = [ $payload = [
'request_id' => $requestId, 'request_id' => $requestId,
'request_date' => $requestDate,
'token' => $token, 'token' => $token,
]; ];
$res = $client->post($targetVerifyUrl, [ $res = $client->post($targetVerifyUrl, [

View File

@@ -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/request_date/token签名 canonical 含 merchant_code;相对路径:拼基址 + 商户体 // 完整 https URL回调 Body request_id+token签名 request_id&tokenHMAC 同 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',

View File

@@ -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` 该地址;**`X-Request-Signature` 与 angpow-imports 同源**JSON Body 为 **`request_id``request_date``token`**`request_date` 为对端必填);签名 canonical 含 **`merchant_code`(配置项,仅用于签名)**;需 **`PLAYX_ANGPOW_MERCHANT_CODE`**、**`PLAYX_ANGPOW_IMPORT_AUTH_KEY`**无需 `PLAYX_ANGPOW_IMPORT_BASE_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`
- **相对路径**(如 `/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**`X-Request-Signature` angpow-imports 同源Body 为 **`request_id``request_date``token`**`merchant_code` 仅参与签名字符串H5 不参与签名。 -`PLAYX_TOKEN_VERIFY_URL` 为**完整 https URL**Body 仅 **`request_id``token`**(与 PlayX 文档一致);`X-Request-Signature` angpow 同源 HMAC明文 **`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
@@ -222,15 +222,13 @@ 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**:与 **`PLAYX_ANGPOW_IMPORT_PATH`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**(与 angpow 同源算法,字段名与对端必填 `request_date` 对齐): - **签名明文 canonical**`request_id={request_id}&token={token}`(与 JSON Body 字段一致,无 `merchant_code` / `request_date`)。
`merchant_code={PLAYX_ANGPOW_MERCHANT_CODE}&request_date={request_date}&request_id={request_id}&token={token}``request_date` 为 Unix 秒时间戳字符串;`merchant_code` 仅参与签名,**不写入** JSON Body - **请求 Body**(与 PlayX 平台 Token 校验文档一致):
- **请求 Body**(对端校验必填 `request_date`,并与 PlayX 文档一致保留 `request_id``token`
| 字段名 | 类型 | 必填 | 说明 | | 字段名 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| `request_id` | String | 是 | 商城生成的请求追踪号。 | | `request_id` | String | 是 | 商城生成的请求追踪号。 |
| `request_date` | String | 是 | Unix 秒时间戳字符串,须与参与签名的 `request_date` 一致。 |
| `token` | String | 是 | 前端传入的 playX 临时凭证。 | | `token` | String | 是 | 前端传入的 playX 临时凭证。 |
请求示例: 请求示例:
@@ -238,7 +236,6 @@ flowchart LR
```json ```json
{ {
"request_id": "mall_20260319_9f1b6d", "request_id": "mall_20260319_9f1b6d",
"request_date": "1700000000",
"token": "eyJhbGciOi..." "token": "eyJhbGciOi..."
} }
``` ```

View File

@@ -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``request_date``token`**`X-Request-Signature` 与 angpow-imports 同源canonical 为 `merchant_code=...&request_date=...&request_id=...&token=...``merchant_code` 来自配置,仅用于签名) - 商城请求上游回调地址时Body **仅** **`request_id``token`**(与 PlayX 文档一致)`X-Request-Signature` 与 angpow-imports **同源算法**canonical 为 **`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`/`request_date`/`token`,签名 canonical 含配置项 `merchant_code`**相对路径**:拼基地址 + 商户四字段 | | `PLAYX_TOKEN_VERIFY_URL` | **完整 `https://` URL**:回调 Body `request_id`+`token`,签名明文同字段**相对路径**:拼基地址 + 商户四字段 |
| `PLAYX_ANGPOW_MERCHANT_CODE` | 回调仅写入签名字符串;相对路径同时进 Body | | `PLAYX_ANGPOW_MERCHANT_CODE` | **相对路径** `verify-token` 需要 |
| `PLAYX_ANGPOW_IMPORT_AUTH_KEY` | 回调与相对路径的 HMAC 密钥(与 angpow-imports 相同) | | `PLAYX_ANGPOW_IMPORT_AUTH_KEY` | 回调与相对路径的 HMAC 密钥(与 angpow-imports 相同) |
--- ---