From 597b1cf58763650751ab2ea53b77e7b896a20477 Mon Sep 17 00:00:00 2001 From: zhx Date: Mon, 25 May 2026 16:33:18 +0800 Subject: [PATCH] fix: prioritize zeeone app access token session --- .../internal/service/game/service_test.go | 45 +++++++++++++++++++ .../internal/service/game/zeeone_adapter.go | 7 +++ 2 files changed, 52 insertions(+) diff --git a/services/game-service/internal/service/game/service_test.go b/services/game-service/internal/service/game/service_test.go index 31f474c4..c3bbb2e6 100644 --- a/services/game-service/internal/service/game/service_test.go +++ b/services/game-service/internal/service/game/service_test.go @@ -816,6 +816,51 @@ func TestHandleZeeOneUserInfoChangeBalanceAndUpdateSession(t *testing.T) { } } +func TestHandleZeeOneAccessTokenIgnoresStaleLaunchSessionGameID(t *testing.T) { + secret := "zeeone-test-secret" + token := leaderccTestAccessToken(t, "lalu", 123456, "123456", 1700003600) + repo := &fakeRepository{ + platform: gamedomain.Platform{ + PlatformCode: "zeeone", + AdapterType: gamedomain.AdapterZeeOneV1, + CallbackSecretCiphertext: secret, + AdapterConfigJSON: `{"merchant_id":307715,"platform_id":2032,"uid_mode":"display_user_id"}`, + }, + // 同一个 App access token 启动过其他 ZeeOne 游戏时,旧启动会话会留下同 hash 但不同 provider_game_id。 + // 回调必须以 JWT 用户身份为准,不能被旧会话的 game_id 拦截成 sessionId invalid。 + session: gamedomain.LaunchSession{ + AppCode: "lalu", + SessionID: "old_launch_session", + UserID: 123456, + DisplayUserID: "123456", + ProviderGameID: "1021", + LaunchTokenHash: stableHash(token), + Status: gamedomain.SessionActive, + ExpiresAtMS: 1700003600000, + }, + } + wallet := &fakeWallet{balanceAfter: 900} + svc := New(Config{}, repo, wallet, &fakeUser{}) + svc.now = func() time.Time { return time.UnixMilli(1700000000000) } + + changeBody := `{"appId":"M307715_P2032","userId":"123456","sessionId":"` + token + `","currency_diff":-100,"diff_msg":"bet","game_id":1032,"room_id":"6","change_time_at":1700000000,"order_id":"zee_order_stale_session"}` + raw, _, err := svc.HandleCallback(context.Background(), &gamev1.CallbackRequest{ + Meta: &gamev1.RequestMeta{RequestId: "req-zeeone-stale-session", AppCode: "lalu"}, + PlatformCode: "zeeone", + Operation: "change_balance", + RawBody: zeeoneTestEnvelope(t, secret, changeBody, 1700000000000), + }) + if err != nil { + t.Fatalf("HandleCallback change failed: %v", err) + } + if !strings.Contains(string(raw), `"code":0`) || strings.Contains(string(raw), "sessionId invalid") { + t.Fatalf("zeeone access token should ignore stale launch session game id: %s", raw) + } + if wallet.lastApply.GetUserId() != 123456 || wallet.lastApply.GetGameId() != "1032" { + t.Fatalf("zeeone wallet command must use JWT user and callback game id, got %+v", wallet.lastApply) + } +} + func TestHandleBaishunSSTokenUserInfoUpdateAndChangeBalance(t *testing.T) { secret := "baishun-test-app-key" token := "app_access_token_baishun" diff --git a/services/game-service/internal/service/game/zeeone_adapter.go b/services/game-service/internal/service/game/zeeone_adapter.go index 30eaa7cd..3f0127f3 100644 --- a/services/game-service/internal/service/game/zeeone_adapter.go +++ b/services/game-service/internal/service/game/zeeone_adapter.go @@ -325,6 +325,13 @@ func (s *Service) validZeeOneSession(ctx context.Context, app string, sessionID if sessionID == "" { return gamedomain.LaunchSession{}, xerr.New(xerr.Unauthorized, "sessionId not found") } + // ZeeOne 约定 sessionId 直接使用 App access token;同一个登录 token 可能启动多款游戏。 + // 因此 JWT 必须优先解析,否则会先命中 game_launch_sessions 里旧游戏的 hash,导致 game_id 校验误判。 + if strings.Count(sessionID, ".") == 2 { + if session, err := s.appSessionFromAccessToken(app, sessionID); err == nil { + return session, nil + } + } if session, err := s.validYomiSession(ctx, app, sessionID); err == nil { return session, nil }