feat: Goa GEL Blockchain e-Licensing Platform - Full Stack Implementation
Complete implementation of the Goa Government e-Licensing platform with: Backend: - NestJS API with JWT authentication - PostgreSQL database with Knex ORM - Redis caching and session management - MinIO document storage - Hyperledger Besu blockchain integration - Multi-department workflow system - Comprehensive API tests (266/282 passing) Frontend: - Angular 21 with standalone components - Angular Material + TailwindCSS UI - Visual workflow builder - Document upload with progress tracking - Blockchain explorer integration - Role-based dashboards (Admin, Department, Citizen) - E2E tests with Playwright (37 tests) Infrastructure: - Docker Compose orchestration - Blockscout blockchain explorer - Development and production configurations
This commit is contained in:
41
backend/src/modules/auth/strategies/api-key.strategy.ts
Normal file
41
backend/src/modules/auth/strategies/api-key.strategy.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { Injectable, UnauthorizedException } from '@nestjs/common';
|
||||
import { PassportStrategy } from '@nestjs/passport';
|
||||
import { Strategy } from 'passport-jwt';
|
||||
import { Request } from 'express';
|
||||
import { AuthService } from '../auth.service';
|
||||
import { API_KEY_HEADER, DEPARTMENT_CODE_HEADER } from '../../../common/constants';
|
||||
|
||||
@Injectable()
|
||||
export class ApiKeyStrategy extends PassportStrategy(Strategy, 'api-key') {
|
||||
constructor(private readonly authService: AuthService) {
|
||||
super({
|
||||
jwtFromRequest: (req: Request) => {
|
||||
const apiKey = req.headers[API_KEY_HEADER] as string;
|
||||
const departmentCode = req.headers[DEPARTMENT_CODE_HEADER] as string;
|
||||
|
||||
if (!apiKey || !departmentCode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Return a dummy token - actual validation happens in validate()
|
||||
return `${apiKey}:${departmentCode}`;
|
||||
},
|
||||
secretOrKey: 'api-key-strategy',
|
||||
});
|
||||
}
|
||||
|
||||
async validate(token: string): Promise<{ departmentId: string; departmentCode: string }> {
|
||||
const [apiKey, departmentCode] = token.split(':');
|
||||
|
||||
if (!apiKey || !departmentCode) {
|
||||
throw new UnauthorizedException('API key and department code are required');
|
||||
}
|
||||
|
||||
const result = await this.authService.validateDepartmentApiKey(apiKey, departmentCode);
|
||||
|
||||
return {
|
||||
departmentId: result.department.id,
|
||||
departmentCode: result.department.code,
|
||||
};
|
||||
}
|
||||
}
|
||||
28
backend/src/modules/auth/strategies/jwt.strategy.ts
Normal file
28
backend/src/modules/auth/strategies/jwt.strategy.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { Injectable, UnauthorizedException } from '@nestjs/common';
|
||||
import { PassportStrategy } from '@nestjs/passport';
|
||||
import { ExtractJwt, Strategy } from 'passport-jwt';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { AuthService } from '../auth.service';
|
||||
import { JwtPayload } from '../../../common/interfaces/request-context.interface';
|
||||
|
||||
@Injectable()
|
||||
export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
|
||||
constructor(
|
||||
private readonly configService: ConfigService,
|
||||
private readonly authService: AuthService,
|
||||
) {
|
||||
super({
|
||||
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
||||
ignoreExpiration: false,
|
||||
secretOrKey: configService.get<string>('JWT_SECRET'),
|
||||
});
|
||||
}
|
||||
|
||||
async validate(payload: JwtPayload): Promise<JwtPayload> {
|
||||
try {
|
||||
return await this.authService.validateJwtPayload(payload);
|
||||
} catch {
|
||||
throw new UnauthorizedException('Invalid token');
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user