Files
image-apiv3/app/lib/api-auth.ts
Beyhan Oğur 031582ea2c first commit
2026-04-26 22:11:03 +03:00

215 lines
5.1 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { NextRequest } from "next/server";
import { db } from "@/db";
import { apiKeys, user } from "@/db/schema";
import { eq, and } from "drizzle-orm";
import { verifyJWT, isValidAPIKeyFormat } from "./jwt";
import { UserRole } from "./permissions";
import { auth } from "@/app/lib/auth";
export interface AuthenticatedRequest extends NextRequest {
userId?: string;
email?: string;
role?: UserRole;
}
export interface AuthResult {
authenticated: boolean;
userId?: string;
email?: string;
role?: UserRole;
error?: string;
}
/**
* API isteklerini doğrula (JWT token veya API key ile)
*
* Kullanım:
* const authResult = await authenticateAPIRequest(request);
* if (!authResult.authenticated) {
* return NextResponse.json({ error: authResult.error }, { status: 401 });
* }
* const userId = authResult.userId;
*/
/**
* Cookie oturumu (Better Auth) veya Bearer (JWT / API key) ile doğrula.
* Web arayüzünden yapılan isteklerde session; script/istemci için Authorization kullanılır.
*/
export async function authenticateWebOrAPIRequest(
request: NextRequest
): Promise<AuthResult> {
const session = await auth.api.getSession({
headers: request.headers,
});
if (session?.user) {
const u = session.user as { id: string };
try {
const users = await db
.select()
.from(user)
.where(eq(user.id, u.id))
.limit(1);
if (users.length === 0) {
return { authenticated: false, error: "Kullanıcı bulunamadı." };
}
const userData = users[0];
return {
authenticated: true,
userId: u.id,
email: userData.email,
role: (userData.role as UserRole) || "user",
};
} catch (error) {
console.error("Session user lookup error:", error);
return {
authenticated: false,
error: "Kimlik doğrulama sırasında bir hata oluştu.",
};
}
}
return authenticateAPIRequest(request);
}
export async function authenticateAPIRequest(request: NextRequest): Promise<AuthResult> {
const authHeader = request.headers.get("authorization");
if (!authHeader) {
return {
authenticated: false,
error: "Authorization header eksik. Bearer token veya API key gerekli.",
};
}
// Bearer token kontrolü
if (authHeader.startsWith("Bearer ")) {
const token = authHeader.substring(7);
// JWT token mu yoksa API key mi?
if (isValidAPIKeyFormat(token)) {
// API Key doğrulama
return await validateAPIKey(token);
} else {
// JWT token doğrulama
return await validateJWTToken(token);
}
}
return {
authenticated: false,
error: "Geçersiz authorization formatı. 'Bearer <token>' formatında olmalı.",
};
}
/**
* JWT token doğrula ve kullanıcı bilgilerini getir
*/
async function validateJWTToken(token: string): Promise<AuthResult> {
const payload = verifyJWT(token);
if (!payload) {
return {
authenticated: false,
error: "Geçersiz veya süresi dolmuş token.",
};
}
// Kullanıcı bilgilerini DB'den al (role için)
try {
const users = await db
.select()
.from(user)
.where(eq(user.id, payload.userId))
.limit(1);
if (users.length === 0) {
return {
authenticated: false,
error: "Kullanıcı bulunamadı.",
};
}
const userData = users[0];
return {
authenticated: true,
userId: payload.userId,
email: payload.email,
role: (userData.role as UserRole) || "user",
};
} catch (error) {
console.error("User lookup error:", error);
return {
authenticated: false,
error: "Kimlik doğrulama sırasında bir hata oluştu.",
};
}
}
/**
* API key doğrula (veritabanından kontrol)
*/
async function validateAPIKey(key: string): Promise<AuthResult> {
try {
const apiKey = await db
.select()
.from(apiKeys)
.where(and(eq(apiKeys.key, key), eq(apiKeys.isActive, true)))
.limit(1);
if (apiKey.length === 0) {
return {
authenticated: false,
error: "Geçersiz API key.",
};
}
const keyData = apiKey[0];
// Süre kontrolü
if (keyData.expiresAt && keyData.expiresAt < new Date()) {
return {
authenticated: false,
error: "API key süresi dolmuş.",
};
}
// Kullanıcı bilgilerini al
const users = await db
.select()
.from(user)
.where(eq(user.id, keyData.userId))
.limit(1);
if (users.length === 0) {
return {
authenticated: false,
error: "Kullanıcı bulunamadı.",
};
}
const userData = users[0];
// Son kullanım tarihini güncelle (opsiyonel)
await db
.update(apiKeys)
.set({ lastUsedAt: new Date() })
.where(eq(apiKeys.id, keyData.id));
return {
authenticated: true,
userId: keyData.userId,
email: userData.email,
role: (userData.role as UserRole) || "user",
};
} catch (error) {
console.error("API key doğrulama hatası:", error);
return {
authenticated: false,
error: "Kimlik doğrulama sırasında bir hata oluştu.",
};
}
}