security: 隐私接口全面加固,统一 token 鉴权
- /api/orders/[id] 只返回 id/status/expiresAt,移除 user_name/pay_url 等隐私字段
- /api/orders/[id]/cancel 改为 token 鉴权,服务端验证用户身份后执行取消
- /api/orders (POST 响应) 过滤 userName/userBalance,不向客户端暴露
- /api/user 移除 username/email/balance,只返回 id/status 和 config
- /api/users/[id] 只返回 {id, exists},不暴露任何隐私信息
- pay/page.tsx 恢复从服务端动态获取 config,无 token 时只显示用户 ID
- pay/orders/page.tsx 无 token 时不查询隐私接口,统一按钮样式
- PaymentQRCode 新增 token prop,无 token 时隐藏取消按钮
- 创建订单失败改为中文错误提示
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { z } from 'zod';
|
||||
import { cancelOrder, OrderError } from '@/lib/order/service';
|
||||
import { getCurrentUserByToken } from '@/lib/sub2api/client';
|
||||
|
||||
const cancelSchema = z.object({
|
||||
user_id: z.number().int().positive(),
|
||||
token: z.string().min(1),
|
||||
});
|
||||
|
||||
export async function POST(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
@@ -13,10 +14,18 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{
|
||||
const parsed = cancelSchema.safeParse(body);
|
||||
|
||||
if (!parsed.success) {
|
||||
return NextResponse.json({ error: '参数错误', details: parsed.error.flatten().fieldErrors }, { status: 400 });
|
||||
return NextResponse.json({ error: '缺少 token 参数' }, { status: 400 });
|
||||
}
|
||||
|
||||
const outcome = await cancelOrder(id, parsed.data.user_id);
|
||||
let userId: number;
|
||||
try {
|
||||
const user = await getCurrentUserByToken(parsed.data.token);
|
||||
userId = user.id;
|
||||
} catch {
|
||||
return NextResponse.json({ error: '登录态已失效,无法取消订单' }, { status: 401 });
|
||||
}
|
||||
|
||||
const outcome = await cancelOrder(id, userId);
|
||||
if (outcome === 'already_paid') {
|
||||
return NextResponse.json({ success: true, status: 'PAID', message: '订单已支付完成' });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user