This commit is contained in:
Vaica committed 2026-06-22 14:59:24 +08:00
1 parent 14f473f89b
commit b1c6878fba
21 files changed
+921 -72

No files matched your search

@@ -0,0 +1,41 @@
import { NextRequest, NextResponse } from "next/server";
import { authenticateUser, getAuthFromRequest } from "@/lib/auth";
// POST /api/auth/login - 登录
export async function POST(request: NextRequest) {
try {
const body = await request.json();
const { username, password } = body;
if (!username || !password) {
return NextResponse.json({ error: "用户名和密码不能为空" }, { status: 400 });
}
const user = authenticateUser(username, password);
if (!user) {
return NextResponse.json({ error: "用户名或密码错误" }, { status: 401 });
}
const token = Buffer.from(`${username}:${Date.now()}`).toString("base64");
return NextResponse.json({
ok: true,
token,
user: { username: user.username, name: user.name, role: user.role },
});
} catch (error: unknown) {
return NextResponse.json(
{ error: error instanceof Error ? error.message : "Unknown error" },
{ status: 500 }
);
}
}
// GET /api/auth/login - 验证当前用户
export async function GET(request: NextRequest) {
const user = getAuthFromRequest(request);
if (!user) {
return NextResponse.json({ error: "未登录" }, { status: 401 });
}
return NextResponse.json({ ok: true, user: { username: user.username, name: user.name, role: user.role } });
}
+13 -2
View File
@@ -1,18 +1,23 @@
import { NextRequest, NextResponse } from "next/server";
import { listPosts, createPost, getPostCount } from "@/lib/posts";
import { cleanExpired } from "@/lib/recycle";
import { getAuthFromRequest } from "@/lib/auth";
export async function GET(request: NextRequest) {
try {
cleanExpired(); // housekeeping on each request
cleanExpired();
const user = getAuthFromRequest(request);
const { searchParams } = request.nextUrl;
const search = searchParams.get("search") || "";
const page = parseInt(searchParams.get("page") || "1", 10);
const perPage = parseInt(searchParams.get("perPage") || "20", 10);
const includeDrafts = searchParams.get("includeDrafts") !== "false";
const result = listPosts({ search, page, perPage, includeDrafts });
// 管理员看所有文章,普通用户只看自己的
const author = user?.role === "admin" ? undefined : user?.name;
const result = listPosts({ search, page, perPage, includeDrafts, author });
const totalCount = getPostCount();
return NextResponse.json({ ...result, totalCount });
@@ -26,6 +31,7 @@ export async function GET(request: NextRequest) {
export async function POST(request: NextRequest) {
try {
const user = getAuthFromRequest(request);
const body = await request.json();
const { frontMatter, content } = body;
@@ -36,6 +42,11 @@ export async function POST(request: NextRequest) {
);
}
// 自动设置作者为当前登录用户
if (user) {
frontMatter.author = user.name;
}
const dirPath = createPost(frontMatter, content || "");
return NextResponse.json({ success: true, dirPath }, { status: 201 });
} catch (error: unknown) {
+161
View File
@@ -0,0 +1,161 @@
import { NextRequest, NextResponse } from "next/server";
import fs from "fs";
import path from "path";
import { getAuthFromRequest, hashPassword, generatePasswordHash } from "@/lib/auth";
interface StoredUser {
username: string;
passwordHash: string;
salt: string;
name: string;
role: "admin" | "user";
}
function getUsersPath(): string {
return path.join(process.cwd(), "users.json");
}
function loadUsers(): StoredUser[] {
try {
const data = JSON.parse(fs.readFileSync(getUsersPath(), "utf-8"));
return data.users || [];
} catch {
return [];
}
}
function saveUsers(users: StoredUser[]): void {
fs.writeFileSync(getUsersPath(), JSON.stringify({ users }, null, 2) + "\n");
}
// GET - 获取用户列表(admin 可看所有,普通用户只看自己)
export async function GET(request: NextRequest) {
const currentUser = getAuthFromRequest(request);
if (!currentUser) {
return NextResponse.json({ error: "未登录" }, { status: 401 });
}
const users = loadUsers();
const safeUsers = users.map(u => ({
username: u.username,
name: u.name,
role: u.role,
}));
if (currentUser.role === "admin") {
return NextResponse.json({ users: safeUsers });
}
return NextResponse.json({
users: safeUsers.filter(u => u.username === currentUser.username),
});
}
// PUT - 修改密码或用户信息
export async function PUT(request: NextRequest) {
const currentUser = getAuthFromRequest(request);
if (!currentUser) {
return NextResponse.json({ error: "未登录" }, { status: 401 });
}
const body = await request.json();
const { targetUsername, oldPassword, newPassword, newName } = body;
const users = loadUsers();
const targetUser = users.find(u => u.username === (targetUsername || currentUser.username));
if (!targetUser) {
return NextResponse.json({ error: "用户不存在" }, { status: 404 });
}
// 普通用户只能改自己
if (currentUser.role !== "admin" && targetUser.username !== currentUser.username) {
return NextResponse.json({ error: "无权修改其他用户" }, { status: 403 });
}
// 修改密码
if (newPassword) {
// 非 admin 修改自己的密码需要验证旧密码
if (currentUser.role !== "admin" || targetUser.username === currentUser.username) {
if (!oldPassword) {
return NextResponse.json({ error: "请输入旧密码" }, { status: 400 });
}
const oldHash = hashPassword(oldPassword, targetUser.salt);
if (oldHash !== targetUser.passwordHash) {
return NextResponse.json({ error: "旧密码错误" }, { status: 400 });
}
}
const { hash, salt } = generatePasswordHash(newPassword);
targetUser.passwordHash = hash;
targetUser.salt = salt;
}
// 修改昵称
if (newName) {
targetUser.name = newName;
}
saveUsers(users);
return NextResponse.json({ ok: true, message: "修改成功" });
}
// POST - 添加用户(仅 admin)
export async function POST(request: NextRequest) {
const currentUser = getAuthFromRequest(request);
if (!currentUser || currentUser.role !== "admin") {
return NextResponse.json({ error: "仅管理员可添加用户" }, { status: 403 });
}
const body = await request.json();
const { username, password, name, role } = body;
if (!username || !password || !name) {
return NextResponse.json({ error: "用户名、密码、昵称不能为空" }, { status: 400 });
}
const users = loadUsers();
if (users.find(u => u.username === username)) {
return NextResponse.json({ error: "用户名已存在" }, { status: 400 });
}
const { hash, salt } = generatePasswordHash(password);
users.push({
username,
passwordHash: hash,
salt,
name,
role: role || "user",
});
saveUsers(users);
return NextResponse.json({ ok: true, message: "用户添加成功" });
}
// DELETE - 删除用户(仅 admin)
export async function DELETE(request: NextRequest) {
const currentUser = getAuthFromRequest(request);
if (!currentUser || currentUser.role !== "admin") {
return NextResponse.json({ error: "仅管理员可删除用户" }, { status: 403 });
}
const { searchParams } = request.nextUrl;
const targetUsername = searchParams.get("username");
if (!targetUsername) {
return NextResponse.json({ error: "缺少用户名" }, { status: 400 });
}
if (targetUsername === currentUser.username) {
return NextResponse.json({ error: "不能删除自己" }, { status: 400 });
}
const users = loadUsers();
const filtered = users.filter(u => u.username !== targetUsername);
if (filtered.length === users.length) {
return NextResponse.json({ error: "用户不存在" }, { status: 404 });
}
saveUsers(filtered);
return NextResponse.json({ ok: true, message: "用户已删除" });
}