Changes
This commit is contained in:
54
src/plugins/auth.ts
Normal file
54
src/plugins/auth.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { FastifyInstance } from "fastify";
|
||||
import fp from "fastify-plugin";
|
||||
import jwt from "jsonwebtoken";
|
||||
|
||||
export default fp(async (server: FastifyInstance) => {
|
||||
server.addHook("preHandler", async (req, reply) => {
|
||||
|
||||
try {
|
||||
// 1) Token aus Cookie lesen
|
||||
const cookieToken = req.cookies?.token
|
||||
|
||||
// 2) Token aus Header lesen (falls Cookie nicht da ist)
|
||||
const authHeader = req.headers.authorization
|
||||
const headerToken = authHeader?.startsWith("Bearer ")
|
||||
? authHeader.slice(7)
|
||||
: null
|
||||
|
||||
let token = null
|
||||
|
||||
if(headerToken !== null && headerToken.length > 10){
|
||||
token = headerToken
|
||||
} else if(cookieToken ){
|
||||
token = cookieToken
|
||||
}
|
||||
|
||||
if (!token) {
|
||||
return // keine Exception → Route darf z. B. public sein
|
||||
}
|
||||
|
||||
|
||||
const payload = jwt.verify(token, process.env.JWT_SECRET!) as {
|
||||
user_id: string;
|
||||
email: string;
|
||||
tenant_id?: string;
|
||||
role?: string;
|
||||
};
|
||||
|
||||
(req as any).user = payload;
|
||||
} catch (err) {
|
||||
return reply.code(401).send({ error: "Invalid or expired token" });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
declare module "fastify" {
|
||||
interface FastifyRequest {
|
||||
user?: {
|
||||
user_id: string;
|
||||
email: string;
|
||||
tenant_id?: string;
|
||||
role?: string;
|
||||
};
|
||||
}
|
||||
}
|
||||
16
src/plugins/cors.ts
Normal file
16
src/plugins/cors.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { FastifyInstance } from "fastify";
|
||||
import fp from "fastify-plugin";
|
||||
import cors from "@fastify/cors";
|
||||
|
||||
export default fp(async (server: FastifyInstance) => {
|
||||
await server.register(cors, {
|
||||
origin: [
|
||||
"http://localhost:3000", // dein Nuxt-Frontend
|
||||
"http://127.0.0.1:3000", // dein Nuxt-Frontend
|
||||
],
|
||||
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
|
||||
allowedHeaders: ["Content-Type", "Authorization", "Context"],
|
||||
exposedHeaders: ["Authorization"], // optional, falls du ihn auch auslesen willst
|
||||
credentials: true, // wichtig, falls du Cookies nutzt
|
||||
});
|
||||
});
|
||||
19
src/plugins/supabase.ts
Normal file
19
src/plugins/supabase.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { FastifyInstance } from "fastify";
|
||||
import fp from "fastify-plugin";
|
||||
import { createClient, SupabaseClient } from "@supabase/supabase-js";
|
||||
|
||||
export default fp(async (server: FastifyInstance) => {
|
||||
const supabaseUrl = process.env.SUPABASE_URL || "https://uwppvcxflrcsibuzsbil.supabase.co";
|
||||
const supabaseServiceKey = process.env.SUPABASE_SERVICE_ROLE_KEY || "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InV3cHB2Y3hmbHJjc2lidXpzYmlsIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTcwMDkzODE5NCwiZXhwIjoyMDE2NTE0MTk0fQ.6hOkD1J8XBkVJUm-swv0ngLQ74xrEYr28EEbo0rUrts";
|
||||
|
||||
const supabase: SupabaseClient = createClient(supabaseUrl, supabaseServiceKey);
|
||||
|
||||
// Fastify um supabase erweitern
|
||||
server.decorate("supabase", supabase);
|
||||
});
|
||||
|
||||
declare module "fastify" {
|
||||
interface FastifyInstance {
|
||||
supabase: SupabaseClient;
|
||||
}
|
||||
}
|
||||
29
src/plugins/swagger.ts
Normal file
29
src/plugins/swagger.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { FastifyInstance } from "fastify";
|
||||
import fp from "fastify-plugin";
|
||||
import swagger from "@fastify/swagger";
|
||||
import swaggerUi from "@fastify/swagger-ui";
|
||||
|
||||
export default fp(async (server: FastifyInstance) => {
|
||||
await server.register(swagger, {
|
||||
mode: "dynamic", // wichtig: generiert echtes OpenAPI JSON
|
||||
openapi: {
|
||||
info: {
|
||||
title: "Multi-Tenant API",
|
||||
description: "API Dokumentation für dein Backend",
|
||||
version: "1.0.0",
|
||||
},
|
||||
servers: [{ url: "http://localhost:3000" }],
|
||||
},
|
||||
});
|
||||
|
||||
await server.register(swaggerUi, {
|
||||
routePrefix: "/docs", // UI erreichbar unter http://localhost:3000/docs
|
||||
swagger: {
|
||||
info: {
|
||||
title: "Multi-Tenant API",
|
||||
version: "1.0.0",
|
||||
},
|
||||
},
|
||||
exposeRoute: true,
|
||||
});
|
||||
});
|
||||
44
src/plugins/tenant.ts
Normal file
44
src/plugins/tenant.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { FastifyInstance, FastifyRequest } from "fastify";
|
||||
import fp from "fastify-plugin";
|
||||
|
||||
export default fp(async (server: FastifyInstance) => {
|
||||
server.addHook("preHandler", async (req, reply) => {
|
||||
const host = req.headers.host?.split(":")[0]; // Domain ohne Port
|
||||
if (!host) {
|
||||
reply.code(400).send({ error: "Missing host header" });
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(host)
|
||||
|
||||
// Tenant aus DB laden
|
||||
const { data: tenant } = await server.supabase
|
||||
.from("tenants")
|
||||
.select("*")
|
||||
.eq("portalDomain", host)
|
||||
.single();
|
||||
|
||||
|
||||
if(!tenant) {
|
||||
// Multi Tenant Mode
|
||||
(req as any).tenant = null;
|
||||
}else {
|
||||
// Tenant ins Request-Objekt hängen
|
||||
(req as any).tenant = tenant;
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
// Typ-Erweiterung
|
||||
declare module "fastify" {
|
||||
interface FastifyRequest {
|
||||
tenant?: {
|
||||
id: string;
|
||||
name: string;
|
||||
domain?: string;
|
||||
subdomain?: string;
|
||||
settings?: Record<string, any>;
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user