feat(auth): mark test accounts in login requests

This commit is contained in:
2026-06-26 14:05:53 +08:00
parent 8cb60ed7e3
commit abf6d5ae88
16 changed files with 78 additions and 36 deletions
@@ -8,7 +8,7 @@ import type { FetchHook } from "ofetch";
import { ApiPath } from "../../../data/services/api/api_path";
import { ApiError, ErrorCode } from "../../../data/services/api/api_result";
import { AuthStorage } from "@/data/storage/auth/auth_storage";
import { deviceIdentifier, Result } from "@/utils";
import { AppEnvUtil, deviceIdentifier, Result } from "@/utils";
/**
* 不需要 auth token 刷新的路径
@@ -105,7 +105,7 @@ async function refreshGuestToken(baseUrl: string): Promise<void> {
const response = await fetch(`${baseUrl}${ApiPath.guestLogin}`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ deviceId }),
body: JSON.stringify(withTestAccountFlag({ deviceId })),
});
if (!response.ok) {
@@ -125,6 +125,12 @@ async function refreshGuestToken(baseUrl: string): Promise<void> {
}
}
function withTestAccountFlag<T extends Record<string, unknown>>(
payload: T,
): T & { isTestAccount: boolean } {
return { ...payload, isTestAccount: !AppEnvUtil.isProduction() };
}
/**
* 401 → 刷新 token 并重试
*/
+1
View File
@@ -10,6 +10,7 @@ import {
export class AppleLoginRequest {
declare readonly identityToken: string;
declare readonly platform: string;
declare readonly isTestAccount: boolean;
private constructor(input: AppleLoginRequestInput) {
const data = AppleLoginRequestSchema.parse(input);
@@ -11,6 +11,7 @@ export class FacebookLoginRequest {
declare readonly accessToken: string;
declare readonly platform: string;
declare readonly guestId: string;
declare readonly isTestAccount: boolean;
private constructor(input: FacebookLoginRequestInput) {
const data = FacebookLoginRequestSchema.parse(input);
+1
View File
@@ -10,6 +10,7 @@ import {
export class FbIdLoginRequest {
declare readonly fbId: string;
declare readonly avatarUrl: string;
declare readonly isTestAccount: boolean;
private constructor(input: FbIdLoginRequestInput) {
const data = FbIdLoginRequestSchema.parse(input);
@@ -11,6 +11,7 @@ export class GoogleLoginRequest {
declare readonly idToken: string;
declare readonly platform: string;
declare readonly guestId: string;
declare readonly isTestAccount: boolean;
private constructor(input: GoogleLoginRequestInput) {
const data = GoogleLoginRequestSchema.parse(input);
+1
View File
@@ -9,6 +9,7 @@ import {
export class GuestLoginRequest {
declare readonly deviceId: string;
declare readonly isTestAccount: boolean;
private constructor(input: GuestLoginRequestInput) {
const data = GuestLoginRequestSchema.parse(input);
+1
View File
@@ -13,6 +13,7 @@ export class LoginRequest {
declare readonly password: string;
declare readonly platform: string;
declare readonly guestId: string;
declare readonly isTestAccount: boolean;
private constructor(input: LoginRequestInput) {
const data = LoginRequestSchema.parse(input);
+1
View File
@@ -13,6 +13,7 @@ export class RegisterRequest {
declare readonly password: string;
declare readonly platform: string;
declare readonly guestId: string;
declare readonly isTestAccount: boolean;
private constructor(input: RegisterRequestInput) {
const data = RegisterRequestSchema.parse(input);
+30 -8
View File
@@ -28,7 +28,7 @@ import {
SendCodeRequest,
} from "@/data/dto/auth";
import { User } from "@/data/dto/user";
import { Result, Logger } from "@/utils";
import { AppEnvUtil, Result, Logger } from "@/utils";
import type { IAuthRepository } from "@/data/repositories/interfaces";
import { AuthStorage, type IAuthStorage } from "@/data/storage/auth";
import { UserStorage, type IUserStorage } from "@/data/storage/user";
@@ -37,6 +37,7 @@ const log = new Logger("DataRepositoriesAuthRepository");
/** 硬编码平台名,对齐 Dart `PlatformUtil.platformName.toLowerCase()`Web 平台)。 */
const WEB_PLATFORM = "web";
const TEST_ACCOUNT_FLAG = "isTestAccount";
export class AuthRepository implements IAuthRepository {
constructor(
@@ -59,13 +60,15 @@ export class AuthRepository implements IAuthRepository {
}): Promise<Result<void>> {
return Result.wrap(async () => {
await this.api.register(
RegisterRequest.from({
RegisterRequest.from(
withTestAccountFlag({
username: input.username,
email: input.email,
password: input.password,
platform: WEB_PLATFORM,
guestId: input.guestId ?? "",
}),
),
);
});
}
@@ -79,13 +82,15 @@ export class AuthRepository implements IAuthRepository {
}): Promise<Result<LoginResponse>> {
return Result.wrap(async () => {
const response = await this.api.emailLogin(
LoginRequest.from({
LoginRequest.from(
withTestAccountFlag({
email: input.email ?? "",
username: input.username ?? "",
password: input.password,
platform: WEB_PLATFORM,
guestId: input.guestId ?? "",
}),
),
);
await this._saveLoginData(response);
return response;
@@ -131,7 +136,7 @@ export class AuthRepository implements IAuthRepository {
});
return Result.wrap(async () => {
const response = await this.api.guestLogin(
GuestLoginRequest.from({ deviceId }),
GuestLoginRequest.from(withTestAccountFlag({ deviceId })),
);
log.debug("[AuthRepository.guestLogin] API call SUCCESS (Zod parsed)", {
hasToken: !!response.token,
@@ -160,12 +165,14 @@ export class AuthRepository implements IAuthRepository {
}): Promise<Result<LoginResponse>> {
return this._socialLogin(() =>
this.api.googleLogin(
GoogleLoginRequest.from({
GoogleLoginRequest.from(
withTestAccountFlag({
idToken: input.idToken,
platform: WEB_PLATFORM,
guestId: input.guestId ?? "",
}),
),
),
);
}
@@ -176,12 +183,14 @@ export class AuthRepository implements IAuthRepository {
}): Promise<Result<LoginResponse>> {
return this._socialLogin(() =>
this.api.facebookLogin(
FacebookLoginRequest.from({
FacebookLoginRequest.from(
withTestAccountFlag({
accessToken: input.accessToken,
platform: WEB_PLATFORM,
guestId: input.guestId ?? "",
}),
),
),
);
}
@@ -192,11 +201,13 @@ export class AuthRepository implements IAuthRepository {
}): Promise<Result<LoginResponse>> {
return this._socialLogin(() =>
this.api.facebookIdLogin(
FbIdLoginRequest.from({
FbIdLoginRequest.from(
withTestAccountFlag({
fbId: input.fbId,
avatarUrl: input.avatarUrl ?? "",
}),
),
),
);
}
@@ -208,11 +219,13 @@ export class AuthRepository implements IAuthRepository {
async appleLogin(identityToken: string): Promise<Result<LoginResponse>> {
return this._socialLogin(() =>
this.api.appleLogin(
AppleLoginRequest.from({
AppleLoginRequest.from(
withTestAccountFlag({
identityToken,
platform: WEB_PLATFORM,
}),
),
),
);
}
@@ -305,3 +318,12 @@ export const authRepository = new AuthRepository(
AuthStorage.getInstance(),
UserStorage.getInstance(),
);
function withTestAccountFlag<T extends Record<string, unknown>>(
payload: T,
): T & { isTestAccount: boolean } {
return {
...payload,
[TEST_ACCOUNT_FLAG]: !AppEnvUtil.isProduction(),
};
}
@@ -7,6 +7,7 @@ import { z } from "zod";
export const AppleLoginRequestSchema = z.object({
identityToken: z.string(),
platform: z.string(),
isTestAccount: z.boolean().default(false),
});
export type AppleLoginRequestInput = z.input<typeof AppleLoginRequestSchema>;
@@ -8,6 +8,7 @@ export const FacebookLoginRequestSchema = z.object({
accessToken: z.string(),
platform: z.string(),
guestId: z.string().default(""),
isTestAccount: z.boolean().default(false),
});
export type FacebookLoginRequestInput = z.input<typeof FacebookLoginRequestSchema>;
@@ -7,6 +7,7 @@ import { z } from "zod";
export const FbIdLoginRequestSchema = z.object({
fbId: z.string(),
avatarUrl: z.string().default(""),
isTestAccount: z.boolean().default(false),
});
export type FbIdLoginRequestInput = z.input<typeof FbIdLoginRequestSchema>;
@@ -8,6 +8,7 @@ export const GoogleLoginRequestSchema = z.object({
idToken: z.string(),
platform: z.string(),
guestId: z.string().default(""),
isTestAccount: z.boolean().default(false),
});
export type GoogleLoginRequestInput = z.input<typeof GoogleLoginRequestSchema>;
@@ -6,6 +6,7 @@ import { z } from "zod";
export const GuestLoginRequestSchema = z.object({
deviceId: z.string(),
isTestAccount: z.boolean().default(false),
});
export type GuestLoginRequestInput = z.input<typeof GuestLoginRequestSchema>;
+1
View File
@@ -10,6 +10,7 @@ export const LoginRequestSchema = z.object({
password: z.string(),
platform: z.string(),
guestId: z.string().default(""),
isTestAccount: z.boolean().default(false),
});
export type LoginRequestInput = z.input<typeof LoginRequestSchema>;
@@ -10,6 +10,7 @@ export const RegisterRequestSchema = z.object({
password: z.string(),
platform: z.string(),
guestId: z.string().default(""),
isTestAccount: z.boolean().default(false),
});
export type RegisterRequestInput = z.input<typeof RegisterRequestSchema>;