refactor: 提取 requireUserId/requireUser/requireMembership 校验工具

- 新增 requireUserId:统一 14 处 userId 非空校验,返回 401
- 新增 requireUser:统一 4 处用户存在性检查,返回 404
- validateMembership 升级为 requireMembership,直接抛 403
- 混合校验拆分为 auth(401) + 字段(400),状态码更准确
This commit is contained in:
2026-02-26 18:17:17 +08:00
parent 0595887480
commit 19edcaeeb5
15 changed files with 67 additions and 56 deletions
+16
View File
@@ -1,4 +1,5 @@
import { NextRequest, NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
export class ApiError extends Error {
constructor(
@@ -9,6 +10,21 @@ export class ApiError extends Error {
}
}
/** Validates that value is a non-empty string; throws 401 otherwise. */
export function requireUserId(value: unknown): string {
if (!value || typeof value !== "string") {
throw new ApiError("请先登录", 401);
}
return value;
}
/** Finds user by ID; throws 404 if not found. */
export async function requireUser(userId: string) {
const user = await prisma.user.findUnique({ where: { id: userId } });
if (!user) throw new ApiError("用户不存在", 404);
return user;
}
type RouteContext = { params: Promise<Record<string, string>> };
type RouteHandler = (
+5 -2
View File
@@ -1,4 +1,5 @@
import { prisma } from "@/lib/prisma";
import { ApiError } from "@/lib/api";
export function generateRoomCode(): string {
const chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
@@ -18,11 +19,13 @@ export async function generateUniqueRoomCode(): Promise<string> {
throw new Error("无法生成唯一房间号");
}
export async function validateMembership(roomId: string, userId: string) {
/** Throws 403 if user is not a member of the room. */
export async function requireMembership(roomId: string, userId: string) {
const member = await prisma.blindBoxMember.findUnique({
where: { roomId_userId: { roomId, userId } },
});
return !!member;
if (!member) throw new ApiError("你不是这个房间的成员", 403);
return member;
}
export async function getRoomByCode(code: string) {