5ab74ad9dd
Co-authored-by: Copilot <copilot@github.com>
67 lines
2.0 KiB
TypeScript
67 lines
2.0 KiB
TypeScript
// server/api/auth/register.post.ts
|
|
import type { UserRegisterRequest, UserRegisterResult } from "#shared/types";
|
|
import {
|
|
createUpstreamErrorResponse,
|
|
createErrorResponse,
|
|
createSuccessResponse,
|
|
newApiFetch
|
|
} from "../../utils";
|
|
|
|
/**
|
|
* 允许从请求体透传给上游的字段列表
|
|
* 只有在这里声明过的字段才会被转发,其余字段一律丢弃,防止参数污染
|
|
* 与 NewAPI 文档字段保持一致
|
|
*/
|
|
const REGISTER_FIELDS = [
|
|
"username",
|
|
"password",
|
|
"email",
|
|
"verification_code",
|
|
"aff_code"
|
|
] as const satisfies ReadonlyArray<keyof UserRegisterRequest>;
|
|
|
|
/**
|
|
* POST /api/auth/register
|
|
*
|
|
* 注册流程:
|
|
* 1. 解析并校验前端传来的 JSON 请求体
|
|
* 2. 从请求体里只挑出文档允许的字段组装 payload
|
|
* 3. 通过 newApiFetch 转发到上游 NewAPI 注册接口
|
|
* 4. 将上游结果统一包装为 ApiResponse 格式返回给前端
|
|
*/
|
|
export default defineEventHandler(async (event) => {
|
|
// 读取并反序列化请求体;如果前端没有传 body,readBody 会返回 null
|
|
const requestBody = await readBody<Partial<UserRegisterRequest> | null>(
|
|
event
|
|
);
|
|
|
|
// 防御性校验:请求体只能是 JSON 对象或空,不接受字符串/数字等原始值
|
|
if (requestBody !== null && typeof requestBody !== "object") {
|
|
return createErrorResponse(400, "请求体必须是 JSON 对象");
|
|
}
|
|
|
|
// 白名单过滤:只保留文档里声明的字段,且必须是字符串类型
|
|
const payload: UserRegisterRequest = {};
|
|
for (const field of REGISTER_FIELDS) {
|
|
const value = requestBody?.[field];
|
|
if (typeof value === "string") {
|
|
payload[field] = value;
|
|
}
|
|
}
|
|
|
|
try {
|
|
const result = await newApiFetch<UserRegisterResult>("/api/user/register", {
|
|
method: "POST",
|
|
body: payload,
|
|
headers: {
|
|
"Content-Type": "application/json"
|
|
}
|
|
});
|
|
|
|
// 上游成功
|
|
return createSuccessResponse(result, "注册成功");
|
|
} catch (error) {
|
|
return createUpstreamErrorResponse(error, "注册失败");
|
|
}
|
|
});
|