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:
Nils-Johan Gynther
2026-04-30 12:19:21 +02:00
parent 5231ca42a7
commit 87372f0d15
4 changed files with 37 additions and 6 deletions
+17 -2
View File
@@ -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 { AuthGuard } from '@nestjs/passport';
import { IS_PUBLIC_KEY } from './decorators/public.decorator';
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
private readonly logger = new Logger(JwtAuthGuard.name);
constructor(private reflector: Reflector) {
super();
}
canActivate(context: ExecutionContext) {
canActivate(context: ExecutionContext): boolean | Promise<boolean> | Observable<boolean> {
const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
context.getHandler(),
context.getClass(),
@@ -17,4 +20,16 @@ export class JwtAuthGuard extends AuthGuard('jwt') {
if (isPublic) return true;
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();
}
}
+5 -4
View File
@@ -1,20 +1,21 @@
import { Injectable } from '@nestjs/common';
import { Injectable, Logger } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
private readonly logger = new Logger(JwtStrategy.name);
constructor() {
const secret = process.env.JWT_SECRET;
if (!secret) throw new Error('JWT_SECRET saknas i miljövariabler');
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: secret,
secretOrKey: process.env.JWT_SECRET,
});
}
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 };
}
}
@@ -15,6 +15,19 @@ export class QuickImportController {
FileInterceptor('file', {
storage: memoryStorage(),
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(
@@ -76,6 +76,8 @@ export class QuickImportService {
* Importerar från en uppladdad fil
*/
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';
return this.importFromBuffer(file.buffer, kind);
}