feat: enhance JWT authentication and quick import functionality with logging for better traceability
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
@@ -1,15 +1,18 @@
|
|||||||
import { Injectable, ExecutionContext } from '@nestjs/common';
|
import { Injectable, CanActivate, ExecutionContext, Logger } from '@nestjs/common';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
import { Reflector } from '@nestjs/core';
|
import { Reflector } from '@nestjs/core';
|
||||||
import { AuthGuard } from '@nestjs/passport';
|
import { AuthGuard } from '@nestjs/passport';
|
||||||
import { IS_PUBLIC_KEY } from './decorators/public.decorator';
|
import { IS_PUBLIC_KEY } from './decorators/public.decorator';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class JwtAuthGuard extends AuthGuard('jwt') {
|
export class JwtAuthGuard extends AuthGuard('jwt') {
|
||||||
|
private readonly logger = new Logger(JwtAuthGuard.name);
|
||||||
|
|
||||||
constructor(private reflector: Reflector) {
|
constructor(private reflector: Reflector) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
canActivate(context: ExecutionContext) {
|
canActivate(context: ExecutionContext): boolean | Promise<boolean> | Observable<boolean> {
|
||||||
const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
|
const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
|
||||||
context.getHandler(),
|
context.getHandler(),
|
||||||
context.getClass(),
|
context.getClass(),
|
||||||
@@ -17,4 +20,16 @@ export class JwtAuthGuard extends AuthGuard('jwt') {
|
|||||||
if (isPublic) return true;
|
if (isPublic) return true;
|
||||||
return super.canActivate(context);
|
return super.canActivate(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add logging for user ID in the JWT authentication guard
|
||||||
|
handleRequest(context: ExecutionContext, next: Function) {
|
||||||
|
const request = context.switchToHttp().getRequest();
|
||||||
|
const user = request.user;
|
||||||
|
|
||||||
|
if (user) {
|
||||||
|
this.logger.log(`User ID: ${user.userId}, Username: ${user.username}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return next();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,21 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable, Logger } from '@nestjs/common';
|
||||||
import { PassportStrategy } from '@nestjs/passport';
|
import { PassportStrategy } from '@nestjs/passport';
|
||||||
import { ExtractJwt, Strategy } from 'passport-jwt';
|
import { ExtractJwt, Strategy } from 'passport-jwt';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class JwtStrategy extends PassportStrategy(Strategy) {
|
export class JwtStrategy extends PassportStrategy(Strategy) {
|
||||||
|
private readonly logger = new Logger(JwtStrategy.name);
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
const secret = process.env.JWT_SECRET;
|
|
||||||
if (!secret) throw new Error('JWT_SECRET saknas i miljövariabler');
|
|
||||||
super({
|
super({
|
||||||
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
||||||
ignoreExpiration: false,
|
ignoreExpiration: false,
|
||||||
secretOrKey: secret,
|
secretOrKey: process.env.JWT_SECRET,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async validate(payload: { sub: number; username: string; role: string; isPremium: boolean }) {
|
async validate(payload: { sub: number; username: string; role: string; isPremium: boolean }) {
|
||||||
|
this.logger.log(`Validating token for user ID: ${payload.sub}, Username: ${payload.username}`);
|
||||||
return { userId: payload.sub, username: payload.username, role: payload.role ?? 'user', isPremium: payload.isPremium ?? false };
|
return { userId: payload.sub, username: payload.username, role: payload.role ?? 'user', isPremium: payload.isPremium ?? false };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,19 @@ export class QuickImportController {
|
|||||||
FileInterceptor('file', {
|
FileInterceptor('file', {
|
||||||
storage: memoryStorage(),
|
storage: memoryStorage(),
|
||||||
limits: { fileSize: 10 * 1024 * 1024 },
|
limits: { fileSize: 10 * 1024 * 1024 },
|
||||||
|
fileFilter: (req, file, callback) => {
|
||||||
|
if (
|
||||||
|
file.mimetype === 'application/pdf' ||
|
||||||
|
file.mimetype === 'application/octet-stream' ||
|
||||||
|
file.mimetype === 'image/jpeg' ||
|
||||||
|
file.mimetype === 'image/png' ||
|
||||||
|
file.mimetype === 'image/webp'
|
||||||
|
) {
|
||||||
|
callback(null, true);
|
||||||
|
} else {
|
||||||
|
callback(new Error('Otillåten filtyp. Använd JPEG, PNG, WebP eller PDF.'), false);
|
||||||
|
}
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
async importFromInput(
|
async importFromInput(
|
||||||
|
|||||||
@@ -76,6 +76,8 @@ export class QuickImportService {
|
|||||||
* Importerar från en uppladdad fil
|
* Importerar från en uppladdad fil
|
||||||
*/
|
*/
|
||||||
async importFromUpload(file: Express.Multer.File): Promise<QuickImportResult | ReceiptImportResult> {
|
async importFromUpload(file: Express.Multer.File): Promise<QuickImportResult | ReceiptImportResult> {
|
||||||
|
this.logger.log('MIME-typ:', file.mimetype);
|
||||||
|
this.logger.log('Token:', file.originalname);
|
||||||
const kind = file.mimetype.startsWith('image/') ? 'image' : 'pdf';
|
const kind = file.mimetype.startsWith('image/') ? 'image' : 'pdf';
|
||||||
return this.importFromBuffer(file.buffer, kind);
|
return this.importFromBuffer(file.buffer, kind);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user