@@ -0,0 +1,13 @@
|
||||
import { Controller, Get, Req } from '@nestjs/common';
|
||||
import { Roles } from 'nest-keycloak-connect';
|
||||
|
||||
@Controller('shop')
|
||||
export class UserController {
|
||||
@Get('group')
|
||||
@Roles({ roles: ['shop'] })
|
||||
async getGroups(@Req() req) {
|
||||
return {
|
||||
user: req.user,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
export class HeaderConstants {
|
||||
static readonly AUTHORIZATION = 'authorization';
|
||||
static readonly TRACE_ID = 'x-traceid';
|
||||
|
||||
// Puoi aggiungere qui altri header futuri
|
||||
static readonly CORRELATION_ID = 'x-correlation-id';
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
// apps/gateway/src/common/interceptors/axios-forward.service.ts
|
||||
import { Injectable, OnModuleInit } from '@nestjs/common';
|
||||
import { HttpService } from '@nestjs/axios';
|
||||
import { traceStorage } from '../storage/trace-storage';
|
||||
import { HeaderConstants } from '../constants/headers.constants';
|
||||
|
||||
@Injectable()
|
||||
export class AxiosConfigService implements OnModuleInit {
|
||||
constructor(private readonly httpService: HttpService) {}
|
||||
|
||||
onModuleInit() {
|
||||
// Accediamo all'istanza Axios interna di NestJS
|
||||
const axios = this.httpService.axiosRef;
|
||||
|
||||
axios.interceptors.request.use((config) => {
|
||||
// Recuperiamo i dati dal magazzino ALS
|
||||
const store = traceStorage.getStore();
|
||||
|
||||
if (store) {
|
||||
if (store.authorization) {
|
||||
config.headers[HeaderConstants.AUTHORIZATION] = store.authorization;
|
||||
}
|
||||
if (store.traceId) {
|
||||
config.headers[HeaderConstants.TRACE_ID] = store.traceId;
|
||||
}
|
||||
if (store.correlationId) {
|
||||
config.headers[HeaderConstants.CORRELATION_ID] = store.correlationId;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`[Axios Outgoing] URL: ${config.url}`);
|
||||
console.log(`[Axios Outgoing] Headers:`, config.headers);
|
||||
|
||||
return config;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// apps/gateway/src/common/middleware/trace.middleware.ts
|
||||
import { Injectable, NestMiddleware } from '@nestjs/common';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { traceStorage } from '../storage/trace-storage';
|
||||
import { HeaderConstants } from '../constants/headers.constants';
|
||||
|
||||
@Injectable()
|
||||
export class TraceMiddleware implements NestMiddleware {
|
||||
use(req: any, res: any, next: () => void) {
|
||||
|
||||
// 1. Gestione Authorization: se manca, sarà undefined
|
||||
const auth = req.headers[HeaderConstants.AUTHORIZATION];
|
||||
if (!auth) {
|
||||
console.warn(
|
||||
`[Gateway] Richiesta ricevuta senza header di autorizzazione su: ${req.url}`,
|
||||
);
|
||||
}
|
||||
|
||||
// 2. Gestione TraceID: se manca, ne generiamo uno nuovo (fondamentale per il debug!)
|
||||
const traceId = req.headers[HeaderConstants.TRACE_ID] || uuidv4();
|
||||
const correlationId =
|
||||
req.headers[HeaderConstants.CORRELATION_ID] || uuidv4();
|
||||
|
||||
// Opzionale: rimandiamo il traceId nella risposta per aiutare il frontend
|
||||
res.setHeader(HeaderConstants.TRACE_ID, traceId);
|
||||
|
||||
const store = {
|
||||
authorization: auth,
|
||||
traceId: traceId,
|
||||
correlationId: correlationId,
|
||||
};
|
||||
|
||||
// .run() fa sì che tutto ciò che accade dentro 'next()'
|
||||
// abbia accesso a questo 'store'
|
||||
traceStorage.run(store, () => {
|
||||
next();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
// apps/gateway/src/common/storage/trace-storage.ts
|
||||
import { AsyncLocalStorage } from 'async_hooks';
|
||||
|
||||
export interface TraceContext {
|
||||
authorization?: string;
|
||||
traceId?: string;
|
||||
correlationId?: string;
|
||||
}
|
||||
|
||||
// Creiamo un'istanza globale del magazzino
|
||||
export const traceStorage = new AsyncLocalStorage<TraceContext>();
|
||||
|
||||
Reference in New Issue
Block a user