feat(auth): Better Auth, kullanıcı adı ile giriş, DAL ve proxy
- MongoDB/Mongoose bağlantıları, kayıt kapalı, admin + username plugin, rate limit - DAL: getCurrentUser, requireSession, requireRole, getActionUser - Kullanıcı adı normalizasyonu: İ/I/ı → i (tr-TR 'ADMIN' → 'admın' hatası) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
import "server-only";
|
||||
import { headers } from "next/headers";
|
||||
import { notFound, redirect } from "next/navigation";
|
||||
import { cache } from "react";
|
||||
import type { SessionUser } from "@/features/auth/types";
|
||||
import { getAuth } from "@/lib/auth";
|
||||
import { visibleEmail } from "@/shared/account-email";
|
||||
import type { SystemRole } from "@/shared/schemas/common";
|
||||
|
||||
/**
|
||||
* Data Access Layer — her korumalı sayfa, layout, Server Action ve Route Handler oturumu
|
||||
* BURADAN okur. proxy.ts yalnızca iyimser (cookie var mı?) kontrol yapar; güvenlik bu katmandadır.
|
||||
*/
|
||||
|
||||
type RawUser = {
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
username?: string | null;
|
||||
role?: string | null;
|
||||
banned?: boolean | null;
|
||||
image?: string | null;
|
||||
};
|
||||
|
||||
export function toSessionUser(user: RawUser): SessionUser {
|
||||
return {
|
||||
id: user.id,
|
||||
name: user.name,
|
||||
username: user.username ?? "",
|
||||
email: visibleEmail(user.email),
|
||||
role: user.role === "admin" ? "admin" : "user",
|
||||
image: user.image ?? undefined,
|
||||
};
|
||||
}
|
||||
|
||||
/** İstek başına bir kez çalışır (React cache). Oturum yoksa veya kullanıcı askıdaysa null. */
|
||||
export const getCurrentUser = cache(async (): Promise<SessionUser | null> => {
|
||||
// headers() önce çağrılır: Cache Components prerender'ı burada durur, auth hiç oluşturulmaz.
|
||||
const requestHeaders = await headers();
|
||||
const session = await getAuth().api.getSession({ headers: requestHeaders });
|
||||
if (!session || session.user.banned) return null;
|
||||
return toSessionUser(session.user);
|
||||
});
|
||||
|
||||
/** Sayfa/layout: oturum yoksa /login'e yönlendirir. */
|
||||
export async function requireSession(): Promise<SessionUser> {
|
||||
const user = await getCurrentUser();
|
||||
if (!user) redirect("/login");
|
||||
return user;
|
||||
}
|
||||
|
||||
/** Sayfa/layout: rol yoksa 404 (sayfanın varlığı bile gösterilmez). */
|
||||
export async function requireRole(role: SystemRole): Promise<SessionUser> {
|
||||
const user = await requireSession();
|
||||
if (user.role !== role) notFound();
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Server Action / Route Handler: yönlendirme yapmaz, yetkisizse null döner
|
||||
* (çağıran `fail(...)` veya 401/403 döndürür).
|
||||
*/
|
||||
export async function getActionUser(role?: SystemRole): Promise<SessionUser | null> {
|
||||
const user = await getCurrentUser();
|
||||
if (!user) return null;
|
||||
if (role && user.role !== role) return null;
|
||||
return user;
|
||||
}
|
||||
Reference in New Issue
Block a user