This commit is contained in:
2025-11-24 18:39:57 +03:30
parent 9996ea3b09
commit 2de08b9e65
7 changed files with 44 additions and 33 deletions
+11 -11
View File
@@ -9,7 +9,7 @@ import { UtilsModule } from './modules/utils/utils.module';
// import { HttpModule } from '@nestjs/axios'; // import { HttpModule } from '@nestjs/axios';
// import { httpConfig } from './config/http.config'; // import { httpConfig } from './config/http.config';
import { AuthModule } from './modules/auth/auth.module'; import { AuthModule } from './modules/auth/auth.module';
import { JwtModule } from '@nestjs/jwt'; // import { JwtModule } from '@nestjs/jwt';
import { UploaderModule } from './modules/uploader/uploader.module'; import { UploaderModule } from './modules/uploader/uploader.module';
import { AdminModule } from './modules/admin/admin.module'; import { AdminModule } from './modules/admin/admin.module';
// import { CacheService } from './modules/utils/cache.service'; // import { CacheService } from './modules/utils/cache.service';
@@ -26,16 +26,16 @@ import { ShipmentsModule } from './modules/shipments/shipments.module';
ConfigModule.forRoot({ isGlobal: true, cache: true }), ConfigModule.forRoot({ isGlobal: true, cache: true }),
MikroOrmModule.forRootAsync(dataBaseConfig), MikroOrmModule.forRootAsync(dataBaseConfig),
// CacheModule.registerAsync(cacheConfig()), // CacheModule.registerAsync(cacheConfig()),
JwtModule.registerAsync({ // JwtModule.registerAsync({
useFactory: (configService: ConfigService) => ({ // useFactory: (configService: ConfigService) => ({
global: true, // global: true,
secret: configService.getOrThrow<string>('JWT_SECRET'), // secret: configService.getOrThrow<string>('JWT_SECRET'),
signOptions: { // // signOptions: {
expiresIn: configService.getOrThrow<number>('JWT_EXPIRATION_TIME'), // // expiresIn: configService.getOrThrow<number>('JWT_EXPIRATION_TIME'),
}, // // },
}), // }),
inject: [ConfigService], // inject: [ConfigService],
}), // }),
UserModule, UserModule,
UtilsModule, UtilsModule,
AuthModule, AuthModule,
+3 -3
View File
@@ -22,9 +22,9 @@ import { RefreshToken } from './entities/refresh-token.entity';
useFactory: (configService: ConfigService) => ({ useFactory: (configService: ConfigService) => ({
global: true, global: true,
secret: configService.getOrThrow<string>('JWT_SECRET'), secret: configService.getOrThrow<string>('JWT_SECRET'),
signOptions: { // signOptions: {
expiresIn: configService.getOrThrow<number>('JWT_EXPIRATION_TIME'), // expiresIn: configService.getOrThrow<number>('JWT_EXPIRATION_TIME'),
}, // },
}), }),
inject: [ConfigService], inject: [ConfigService],
}), }),
@@ -31,11 +31,10 @@ export class AdminAuthController {
return this.authService.verifyOtpAdmin(dto.phone, dto.slug, dto.otp); // assuming dto has `otp` property return this.authService.verifyOtpAdmin(dto.phone, dto.slug, dto.otp); // assuming dto has `otp` property
} }
@RefreshTokenRateLimit() @RefreshTokenRateLimit()
@ApiOperation({ summary: 'refresh the admin access token / refresh token' }) @ApiOperation({ summary: 'refresh the admin access token / refresh token' })
@Post('refresh') @Post('refresh')
refreshToken(@Body() refreshTokenDto: RefreshTokenDto) { refreshToken(@Body() refreshTokenDto: RefreshTokenDto) {
return this.authService.refreshToken(refreshTokenDto.refreshToken, true); return this.authService.refreshToken(refreshTokenDto.refreshToken);
} }
} }
@@ -31,12 +31,10 @@ export class AuthController {
return this.authService.verifyOtp(dto.phone, dto.slug, dto.otp); // assuming dto has `otp` property return this.authService.verifyOtp(dto.phone, dto.slug, dto.otp); // assuming dto has `otp` property
} }
@RefreshTokenRateLimit() @RefreshTokenRateLimit()
@ApiOperation({ summary: 'refresh the user access token / refresh token' }) @ApiOperation({ summary: 'refresh the user access token / refresh token' })
@Post('refresh') @Post('refresh')
refreshToken(@Body() refreshTokenDto: RefreshTokenDto) { refreshToken(@Body() refreshTokenDto: RefreshTokenDto) {
return this.authService.refreshToken(refreshTokenDto.refreshToken, false); return this.authService.refreshToken(refreshTokenDto.refreshToken);
} }
} }
+8 -5
View File
@@ -4,8 +4,8 @@ import { JwtService } from '@nestjs/jwt';
import { ConfigService } from '@nestjs/config'; import { ConfigService } from '@nestjs/config';
import { ITokenPayload } from '../interfaces/IToken-payload'; import { ITokenPayload } from '../interfaces/IToken-payload';
export interface AdminAuthRequest extends Request { export interface UserAuthRequest extends Request {
adminId: string; userId: string;
restId: string; restId: string;
} }
@@ -21,10 +21,10 @@ export class AuthGuard implements CanActivate {
) {} ) {}
async canActivate(context: ExecutionContext) { async canActivate(context: ExecutionContext) {
const request = context.switchToHttp().getRequest<AdminAuthRequest>(); const request = context.switchToHttp().getRequest<UserAuthRequest>();
try { try {
const secret = this.configService.get<string>('JWT_SECRET'); const secret = this.configService.getOrThrow<string>('JWT_SECRET');
const token = this.extractTokenFromHeader(request); const token = this.extractTokenFromHeader(request);
if (!token) { if (!token) {
throw new UnauthorizedException(); throw new UnauthorizedException();
@@ -46,7 +46,10 @@ export class AuthGuard implements CanActivate {
return true; return true;
} catch (err) { } catch (err) {
console.log('error in AuthGuard', err); if (err instanceof UnauthorizedException) {
throw err;
}
this.logger.error('error in AuthGuard', err);
throw new UnauthorizedException('Invalid or expired token'); throw new UnauthorizedException('Invalid or expired token');
} }
} }
+2 -2
View File
@@ -101,7 +101,7 @@ export class AuthService {
return code.toString(); return code.toString();
} }
refreshToken(oldRefreshToken: string, isAdmin: boolean) { refreshToken(oldRefreshToken: string) {
return this.tokensService.refreshToken(oldRefreshToken, isAdmin); return this.tokensService.refreshToken(oldRefreshToken);
} }
} }
+15 -4
View File
@@ -57,7 +57,7 @@ export class TokensService {
return this.em.persistAndFlush(token); return this.em.persistAndFlush(token);
} }
async refreshToken(oldRefreshToken: string, isAdmin: boolean) { async refreshToken(oldRefreshToken: string) {
const token = await this.em.findOne(RefreshToken, { token: oldRefreshToken }); const token = await this.em.findOne(RefreshToken, { token: oldRefreshToken });
if (!token) throw new UnauthorizedException(AuthMessage.INVALID_REFRESH_TOKEN); if (!token) throw new UnauthorizedException(AuthMessage.INVALID_REFRESH_TOKEN);
@@ -68,16 +68,27 @@ export class TokensService {
throw new UnauthorizedException(AuthMessage.REFRESH_TOKEN_EXPIRED); throw new UnauthorizedException(AuthMessage.REFRESH_TOKEN_EXPIRED);
} }
// Store token data before removal
const ownerId = token.ownerId;
const restId = token.restId;
// Remove the old token // Remove the old token
this.em.remove(token); this.em.remove(token);
const isAdmin = token.type === RefreshTokenType.ADMIN;
// Generate new tokens within the same transaction try {
const tokens = await this.generateAccessAndRefreshToken(token.ownerId, token.restId, isAdmin); // Generate new tokens
const tokens = await this.generateAccessAndRefreshToken(ownerId, restId, isAdmin);
// Commit the transaction // Commit the transaction
await this.em.flush(); await this.em.flush();
return tokens; return tokens;
} catch (error) {
// If token generation fails, the old token is already removed
// This is acceptable as the token was already used
this.logger.error('Failed to generate new tokens after refresh', error);
throw new UnauthorizedException('Failed to refresh token');
}
} }
private generateRefreshToken() { private generateRefreshToken() {