1.优化ws参数格式auth-token和user-token

This commit is contained in:
2026-05-27 10:57:52 +08:00
parent a96aa0fb41
commit b93940eaee
6 changed files with 147 additions and 35 deletions

View File

@@ -12,11 +12,10 @@ use Throwable;
/**
* WebSocket 握手鉴权助手(与 HTTP §1.3 对齐):
*
* 两种合法身份:
* 1) **mobileH5/移动端)**URL Query 必须带 `auth_token` + `user_token`,校验通过后绑定 user_id
* 两种合法身份URL Query 参数名统一为连字符,与 HTTP 请求头一致)
* 1) **mobileH5/移动端)**:必须带 **`auth-token`** + **`user-token`**,校验通过后绑定 user_id
* 分发器对 user 级主题bet.win 等)按 user_id 过滤,只发本人。
* 2) **admin后台联调/实时对局页)**URL Query 必须带 `auth_token` + `admin_ws_token`
* `admin_ws_token` 由后台 `wsConfig` 接口签发并写入 Redis短时签名。绑定 user_id=0
* 2) **admin后台联调/实时对局页)**必须带 **`admin-ws-token`**(由后台 `wsConfig` 签发,写 Redis 短时签名)。绑定 user_id=0
* 分发器对该连接不做 user 级过滤,可观测全量推送(用于运维/联调)。
*
* 任一身份通过即可建连;都不满足则拒绝握手。
@@ -35,7 +34,23 @@ use Throwable;
*/
final class GameWebSocketAuthHelper
{
/** admin_ws_token 在 Redis 中的 key 前缀value 存 admin_idTTL 由 issueAdminWsToken 决定 */
/** WebSocket 握手 Query 标准参数名(与 HTTP 头 auth-token / user-token 一致,一律用连字符) */
public const QUERY_AUTH_TOKEN = 'auth-token';
public const QUERY_USER_TOKEN = 'user-token';
public const QUERY_ADMIN_WS_TOKEN = 'admin-ws-token';
/** @var list<string> 兼容旧客户端的下划线/驼峰别名(解析时仍可读,拼 URL 时勿用) */
private const LEGACY_AUTH_KEYS = ['auth_token', 'authToken'];
/** @var list<string> */
private const LEGACY_USER_KEYS = ['user_token', 'userToken', 'token'];
/** @var list<string> */
private const LEGACY_ADMIN_KEYS = ['admin_ws_token', 'adminWsToken'];
/** admin-ws-token 在 Redis 中的 key 前缀value 存 admin_idTTL 由 issueAdminWsToken 决定 */
private const ADMIN_TOKEN_REDIS_PREFIX = 'dfw:v1:ws:admin_token:';
private const ADMIN_TOKEN_DEFAULT_TTL = 7200;
@@ -45,9 +60,9 @@ final class GameWebSocketAuthHelper
*/
public static function authorize(array $query): array
{
$authToken = self::pickFirstString($query, ['auth_token', 'auth-token', 'authToken']);
$userToken = self::pickFirstString($query, ['user_token', 'user-token', 'userToken', 'token']);
$adminWsToken = self::pickFirstString($query, ['admin_ws_token', 'admin-ws-token', 'adminWsToken']);
$authToken = self::pickFirstString($query, array_merge([self::QUERY_AUTH_TOKEN], self::LEGACY_AUTH_KEYS));
$userToken = self::pickFirstString($query, array_merge([self::QUERY_USER_TOKEN], self::LEGACY_USER_KEYS));
$adminWsToken = self::pickFirstString($query, array_merge([self::QUERY_ADMIN_WS_TOKEN], self::LEGACY_ADMIN_KEYS));
// ===== Admin 旁路:只校验 admin_ws_token由后台 wsConfig 签发,已隐含管理员身份) =====
if ($adminWsToken !== '') {
@@ -152,6 +167,29 @@ final class GameWebSocketAuthHelper
return $adminId === false ? 0 : (int) $adminId;
}
/**
* 拼装移动端 WebSocket 连接 URLQuery 固定为 auth-token、user-token
*
* @param array<string, string> $extraQuery 其它 Query如 device_id、lang
*/
public static function buildMobileConnectUrl(string $baseWsUrl, string $authToken, string $userToken, array $extraQuery = []): string
{
return \app\common\library\admin\WebSocketConfigHelper::appendTokensToWsUrl($baseWsUrl, [
self::QUERY_AUTH_TOKEN => $authToken,
self::QUERY_USER_TOKEN => $userToken,
], $extraQuery);
}
/**
* 拼装后台 WebSocket 连接 URLQuery 固定为 admin-ws-token
*/
public static function buildAdminConnectUrl(string $baseWsUrl, string $adminWsToken): string
{
return \app\common\library\admin\WebSocketConfigHelper::appendTokensToWsUrl($baseWsUrl, [
self::QUERY_ADMIN_WS_TOKEN => $adminWsToken,
]);
}
/**
* 从 ws header 中解析 GET 行 QueryWorkerman 在 onWebSocketConnect($connection, $request) 时
* $request 可能为字符串或对象;为兼容,这里允许直接传 URI Query 字符串)。