This commit is contained in:
2025-05-22 22:02:54 +07:00
parent 38d1bbf647
commit b2a4cd3f4f
5 changed files with 73 additions and 11 deletions

View File

@@ -36,6 +36,10 @@ import {FilesModule} from "./files/file.module";
S3_BUCKET: Joi.string().required(), S3_BUCKET: Joi.string().required(),
S3_ACCESS_KEY: Joi.string().required(), S3_ACCESS_KEY: Joi.string().required(),
S3_ENDPOINT: Joi.string().required(), S3_ENDPOINT: Joi.string().required(),
JWT_ACCESS_TOKEN_SECRET: Joi.string().required(),
JWT_ACCESS_TOKEN_EXPIRATION_TIME: Joi.string().required(),
JWT_REFRESH_TOKEN_SECRET: Joi.string().required(),
JWT_REFRESH_TOKEN_EXPIRATION_TIME: Joi.string().required(),
}) })
}), }),
UsersModule, UsersModule,
@@ -47,4 +51,5 @@ import {FilesModule} from "./files/file.module";
controllers: [AppController], controllers: [AppController],
providers: [AppService], providers: [AppService],
}) })
export class AppModule {} export class AppModule {
}

View File

@@ -87,4 +87,14 @@ export class AuthenticationController {
return user; return user;
} }
@UseGuards(JwtRefreshGuard)
@Get('refresh')
refresh(@Req() request: RequestWithUser) {
const accessTokenCookie = this.authenticationService.getCookieWithJwtAccessToken(request.user.id);
request.res.setHeader('Set-Cookie', accessTokenCookie);
return request.user;
}
} }

View File

@@ -0,0 +1,30 @@
import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { Request } from 'express';
import {UsersService} from "../users/user.service";
@Injectable()
export class JwtRefreshTokenStrategy extends PassportStrategy(
Strategy,
'jwt-refresh-token'
) {
constructor(
private readonly configService: ConfigService,
private readonly userService: UsersService,
) {
super({
jwtFromRequest: ExtractJwt.fromExtractors([(request: Request) => {
return request?.cookies?.Refresh;
}]),
secretOrKey: configService.get('JWT_REFRESH_TOKEN_SECRET'),
passReqToCallback: true,
});
}
async validate(request: Request, payload: TokenPayload) {
const refreshToken = request.cookies?.Refresh;
return this.userService.getUserIfRefreshTokenMatches(refreshToken, payload.userId);
}
}

View File

@@ -0,0 +1,5 @@
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export default class JwtRefreshGuard extends AuthGuard('jwt-refresh-token') {}

View File

@@ -34,6 +34,19 @@ export class UsersService {
throw new HttpException('User with this id does not exist', HttpStatus.NOT_FOUND); throw new HttpException('User with this id does not exist', HttpStatus.NOT_FOUND);
} }
async getUserIfRefreshTokenMatches(refreshToken: string, userId: number) {
const user = await this.getById(userId);
const isRefreshTokenMatching = await bcrypt.compare(
refreshToken,
user.currentHashedRefreshToken
);
if (isRefreshTokenMatching) {
return user;
}
}
async addAvatar(userId: number, imageBuffer: Buffer, filename: string) { async addAvatar(userId: number, imageBuffer: Buffer, filename: string) {
const avatar = await this.filesService.uploadPublicFile(imageBuffer, filename); const avatar = await this.filesService.uploadPublicFile(imageBuffer, filename);
const user = await this.getById(userId); const user = await this.getById(userId);
@@ -62,5 +75,4 @@ export class UsersService {
currentHashedRefreshToken: null, currentHashedRefreshToken: null,
}); });
} }
} }