This commit is contained in:
@@ -47,6 +47,7 @@ export default function AdminUsersPage() {
|
||||
<table className="w-full text-sm">
|
||||
<thead className="bg-[#f6f4f4] border-b border-[#e6e6e6]">
|
||||
<tr>
|
||||
<th className="px-4 py-2 text-left text-[12px] text-[#8c8c8c]">ID</th>
|
||||
<th className="px-4 py-2 text-left text-[12px] text-[#8c8c8c]">닉네임</th>
|
||||
<th className="px-4 py-2 text-left text-[12px] text-[#8c8c8c]">이름</th>
|
||||
<th className="px-4 py-2 text-left text-[12px] text-[#8c8c8c]">전화</th>
|
||||
@@ -90,6 +91,7 @@ function Row({ u, onChanged }: { u: any; onChanged: () => void }) {
|
||||
const allRoles = ["admin", "editor", "user"] as const;
|
||||
return (
|
||||
<tr className="hover:bg-neutral-50">
|
||||
<td className="px-4 py-2 text-left tabular-nums">{u.userId}</td>
|
||||
<td className="px-4 py-2 text-left">{u.nickname}</td>
|
||||
<td className="px-4 py-2 text-left">{u.name}</td>
|
||||
<td className="px-4 py-2 text-left">{u.phone}</td>
|
||||
|
||||
@@ -148,7 +148,7 @@ export default function HorizontalCardScroller({ items }: HorizontalCardScroller
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pointer-events-none absolute bottom-[-5px] left-1/2 -translate-x-1/2 z-20 flex items-center gap-6">
|
||||
<div className="pointer-events-none absolute bottom-[-5px] left-1/2 -translate-x-1/2 z-20 flex items-center gap-6 w-full">
|
||||
<button
|
||||
type="button"
|
||||
aria-label="이전"
|
||||
@@ -159,7 +159,7 @@ export default function HorizontalCardScroller({ items }: HorizontalCardScroller
|
||||
<path d="M9.5 5.5L15 12l-5.5 6.5" stroke="currentColor" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round" />
|
||||
</svg>
|
||||
</button>
|
||||
<div ref={trackRef} className="pointer-events-auto relative h-1 w-[480px] rounded bg-[#EDEDED]">
|
||||
<div ref={trackRef} className="pointer-events-auto relative h-1 flex-1 min-w-0 max-w-[480px] rounded bg-[#EDEDED]">
|
||||
<div
|
||||
className="absolute top-0 h-1 rounded bg-[var(--red-50,#F94B37)]"
|
||||
style={{ width: `${thumbWidth}px`, left: `${thumbLeft}px` }}
|
||||
|
||||
@@ -43,7 +43,7 @@ export function SendMessageForm({ receiverId, receiverNickname, onSent }: { rece
|
||||
return (
|
||||
<form onSubmit={onSubmit} className="flex flex-col gap-2">
|
||||
<div className="text-sm text-neutral-700">
|
||||
받는 사람: <span className="font-semibold">{receiverNickname || receiverId}</span>
|
||||
받는 사람: <span className="font-semibold">{receiverNickname || "알 수 없음"}</span>
|
||||
</div>
|
||||
<textarea
|
||||
value={body}
|
||||
|
||||
@@ -11,13 +11,51 @@ export async function middleware(req: NextRequest) {
|
||||
const uid = req.cookies.get("uid")?.value;
|
||||
const isAdmin = req.cookies.get("isAdmin")?.value;
|
||||
|
||||
// 세션 검증 엔드포인트 자체에 대해선 미들웨어 검증을 생략 (무한 루프 방지)
|
||||
if (pathname === "/api/auth/session") {
|
||||
return response;
|
||||
}
|
||||
|
||||
// uid 쿠키가 있어도 실제 유저가 존재하지 않으면 비로그인으로 간주하고 쿠키 정리
|
||||
let authenticated = false;
|
||||
if (uid) {
|
||||
try {
|
||||
const verifyUrl = new URL("/api/auth/session", req.url);
|
||||
const verifyRes = await fetch(verifyUrl.toString(), {
|
||||
headers: {
|
||||
// 현재 요청의 쿠키를 전달하여 세션을 검증
|
||||
cookie: req.headers.get("cookie") ?? "",
|
||||
},
|
||||
});
|
||||
if (verifyRes.ok) {
|
||||
const data = await verifyRes.json().catch(() => ({ ok: false }));
|
||||
authenticated = !!data?.ok;
|
||||
}
|
||||
} catch {
|
||||
authenticated = false;
|
||||
}
|
||||
// 유효하지 않은 uid 쿠키는 즉시 제거
|
||||
if (!authenticated) {
|
||||
response.cookies.set("uid", "", { path: "/", maxAge: 0 });
|
||||
response.cookies.set("isAdmin", "", { path: "/", maxAge: 0 });
|
||||
}
|
||||
}
|
||||
|
||||
// Admin 페이지 보호
|
||||
if (pathname.startsWith("/admin")) {
|
||||
console.log("Admin 페이지 접근");
|
||||
console.log("uid", uid);
|
||||
// 비로그인 사용자는 로그인 페이지로
|
||||
if (!uid) {
|
||||
if (!authenticated) {
|
||||
const loginUrl = req.nextUrl.clone();
|
||||
loginUrl.pathname = "/login";
|
||||
return NextResponse.redirect(loginUrl);
|
||||
const res = NextResponse.redirect(loginUrl);
|
||||
// 리다이렉트 응답에도 쿠키 정리 반영
|
||||
if (uid && !authenticated) {
|
||||
res.cookies.set("uid", "", { path: "/", maxAge: 0 });
|
||||
res.cookies.set("isAdmin", "", { path: "/", maxAge: 0 });
|
||||
}
|
||||
return res;
|
||||
}
|
||||
// 로그인했지만 관리자가 아니면 홈으로
|
||||
if (isAdmin !== "1") {
|
||||
@@ -29,7 +67,7 @@ export async function middleware(req: NextRequest) {
|
||||
|
||||
// 로그인된 상태에서 로그인 페이지 접근 시 홈으로 리다이렉트
|
||||
if (pathname === "/login" || pathname.startsWith("/login/")) {
|
||||
if (uid) {
|
||||
if (authenticated) {
|
||||
const homeUrl = req.nextUrl.clone();
|
||||
homeUrl.pathname = "/";
|
||||
return NextResponse.redirect(homeUrl);
|
||||
@@ -37,7 +75,7 @@ export async function middleware(req: NextRequest) {
|
||||
}
|
||||
|
||||
const needAuth = protectedApi.some((re) => re.test(pathname));
|
||||
if (needAuth && !uid) {
|
||||
if (needAuth && !authenticated) {
|
||||
return new NextResponse(JSON.stringify({ error: "Unauthorized" }), { status: 401 });
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user