1459
This commit is contained in:
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 } });
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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: "用户已删除" });
|
||||
}
|
||||
Reference in new issue
Block a user