Add authentication features for admin access

- Introduce a new `auth` module with login, logout, and user verification endpoints for a single admin user.
- Update backend routes to require admin authentication for sensitive operations, enhancing security.
- Modify frontend components to include an authentication provider and gate, ensuring only authorized users can access the application.
- Implement a login page for admin access, improving user experience and security management.
- Update API request handling to redirect unauthorized users to the login page, ensuring proper access control.
This commit is contained in:
Xin Wang
2026-07-09 23:27:50 +08:00
parent d857401ef3
commit 590cb33cbd
20 changed files with 534 additions and 29 deletions
+31 -4
View File
@@ -1,7 +1,7 @@
"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { usePathname, useRouter } from "next/navigation";
import {
Bot,
Boxes,
@@ -11,9 +11,11 @@ import {
Database,
Wrench,
Home,
LogOut,
PlayCircle,
Video,
} from "lucide-react";
import { useAuth } from "@/components/auth/AuthProvider";
type SidebarProps = {
collapsed: boolean;
@@ -39,6 +41,8 @@ const monitorSubItems: NavItem[] = [
export function Sidebar({ collapsed, onToggle }: SidebarProps) {
const pathname = usePathname();
const router = useRouter();
const { user, logout } = useAuth();
// 精确匹配或前缀匹配(带 / 边界),让 /assistants/xxx 也高亮"创建助手"
const isActive = (href: string) =>
@@ -47,6 +51,11 @@ export function Sidebar({ collapsed, onToggle }: SidebarProps) {
const componentActive = componentSubItems.some((item) => isActive(item.href));
const monitorActive = monitorSubItems.some((item) => isActive(item.href));
async function handleLogout() {
await logout();
router.replace("/login");
}
return (
<aside
className={[
@@ -193,10 +202,9 @@ export function Sidebar({ collapsed, onToggle }: SidebarProps) {
</nav>
<div className="shrink-0 space-y-2 border-t border-sidebar-border bg-sidebar p-3 shadow-[0_-12px_24px_rgba(0,0,0,0.12)]">
{/* 个人中心 */}
<Link
href="/profile"
title={collapsed ? "个人中心 · 管理员" : undefined}
title={collapsed ? `个人中心 · ${user?.displayName ?? "超级管理员"}` : undefined}
className={[
"group relative flex w-full items-center overflow-hidden rounded-2xl border py-2 text-left transition-[background-color,color,border-color,box-shadow,transform] duration-200 active:scale-[0.98]",
isActive("/profile")
@@ -229,11 +237,30 @@ export function Sidebar({ collapsed, onToggle }: SidebarProps) {
].join(" ")}
>
<span className="block truncate text-sm font-medium text-foreground">
管理员
{user?.displayName ?? "超级管理员"}
</span>
</span>
</Link>
<button
onClick={handleLogout}
title={collapsed ? "退出登录" : undefined}
className={[
"group flex h-10 w-full items-center overflow-hidden rounded-full border border-hairline-strong text-sm text-muted-foreground transition-[background-color,color,border-color,transform] duration-200 hover:bg-surface-strong hover:text-foreground active:scale-[0.98]",
collapsed ? "justify-center gap-0 px-0" : "justify-between gap-2 px-3.5",
].join(" ")}
>
<span
className={[
"min-w-0 truncate transition-all duration-300 ease-[cubic-bezier(0.22,1,0.36,1)]",
collapsed ? "w-0 opacity-0 -translate-x-2" : "opacity-100 translate-x-0",
].join(" ")}
>
退出登录
</span>
<LogOut size={18} className="shrink-0 transition-transform duration-200 group-hover:translate-x-0.5" />
</button>
{/* 收起 / 展开侧栏 */}
<button
onClick={onToggle}