171 lines
4.0 KiB
TypeScript
171 lines
4.0 KiB
TypeScript
import { NextRequest, NextResponse } 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";
|
||
|
||
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;
|
||
*/
|
||
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.",
|
||
};
|
||
}
|
||
}
|