added session auth check

This commit is contained in:
Igor Hrenowitsch Propisnov 2024-06-05 22:18:08 +02:00
parent fcd147bca4
commit d8f65f1241
10 changed files with 83 additions and 34 deletions

View File

@ -1,19 +1,21 @@
import {
Controller,
Post,
Get,
Body,
HttpCode,
HttpStatus,
Req,
UseGuards,
} from '@nestjs/common';
import { ApiCreatedResponse, ApiTags } from '@nestjs/swagger';
import { ApiBody, ApiCreatedResponse, ApiTags } from '@nestjs/swagger';
import { Request } from 'express';
import { SessionGuard } from 'src/modules/session/guard';
import { SuccessDto } from 'src/shared';
import { Public } from 'src/shared/decorator';
import { LocalAuthGuard } from '../guard';
import { LoginResponseDto, UserCredentialsDto } from '../models/dto';
import { SigninResponseDto, UserCredentialsDto } from '../models/dto';
import { AuthService } from '../services/auth.service';
@ApiTags('Authentication')
@ -23,28 +25,29 @@ export class AuthController {
@ApiCreatedResponse({
description: 'User signed up successfully',
type: LoginResponseDto,
type: SuccessDto,
})
@Public()
@Post('signup')
@HttpCode(HttpStatus.CREATED)
@Public()
public async signup(
@Body() userCredentials: UserCredentialsDto
): Promise<{ success: boolean }> {
): Promise<SuccessDto> {
return this.authService.signup(userCredentials);
}
@ApiCreatedResponse({
description: 'User signin successfully',
type: LoginResponseDto,
type: SigninResponseDto,
})
@ApiBody({ type: UserCredentialsDto })
@HttpCode(HttpStatus.OK)
@Public()
@UseGuards(LocalAuthGuard)
@Public()
@Post('signin')
public async signin(@Req() request: Request): Promise<LoginResponseDto> {
public async signin(@Req() request: Request): Promise<SigninResponseDto> {
return this.authService.getLoginResponse(
request.user as LoginResponseDto & { userAgent: string }
request.user as SigninResponseDto & { userAgent: string }
);
}
@ -54,7 +57,21 @@ export class AuthController {
@HttpCode(HttpStatus.OK)
@UseGuards(SessionGuard)
@Post('logout')
public async logout(@Req() request: Request): Promise<{ success: boolean }> {
public async logout(@Req() request: Request): Promise<SuccessDto> {
return this.authService.logout(request.sessionID);
}
@ApiCreatedResponse({
description: 'Check if user is authenticated',
type: SuccessDto,
})
@HttpCode(HttpStatus.OK)
@UseGuards(SessionGuard)
@Get('status')
public status(@Req() request: Request): Promise<SuccessDto> {
return this.authService.checkAuthStatus(
request.sessionID,
request.headers['user-agent']
);
}
}

View File

@ -1,2 +1,2 @@
export * from './user-credentials.dto';
export * from './login-response.dto';
export * from './signin-response.dto';

View File

@ -1,7 +1,7 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsEmail, IsNotEmpty, IsString } from 'class-validator';
export class LoginResponseDto {
export class SigninResponseDto {
@ApiProperty({
title: 'Email',
description: 'User Email',

View File

@ -30,13 +30,4 @@ export class UserCredentialsRepository {
): Promise<UserCredentials | undefined> {
return this.repository.findOne({ where: { id: userId } });
}
// public async updateUserRefreshToken(
// userId: string,
// refreshToken: string | null
// ): Promise<number> {
// const result = await this.repository.update(userId, { refreshToken });
// return result.affected ?? 0;
// }
}

View File

@ -7,12 +7,12 @@ import {
} from '@nestjs/common';
import { UserCredentials } from 'src/entities';
import { SessionService } from 'src/modules/session/services/session.service';
import { EncryptionService } from 'src/shared';
import { EncryptionService, SuccessDto } from 'src/shared';
import { PasswordConfirmationMailService } from '../../sendgrid-module/services/password-confirmation.mail.service';
import { UserDataRepository } from '../../user-module/repositories/user-data.repository';
import { EmailVerificationService } from '../../verify-module/services/email-verification.service';
import { LoginResponseDto, UserCredentialsDto } from '../models/dto';
import { SigninResponseDto, UserCredentialsDto } from '../models/dto';
import { UserCredentialsRepository } from '../repositories/user-credentials.repository';
@Injectable()
@ -27,7 +27,7 @@ export class AuthService {
public async signup(
userCredentials: UserCredentialsDto
): Promise<{ success: boolean }> {
): Promise<SuccessDto> {
try {
const existingUser = await this.userCredentialsRepository.findUserByEmail(
userCredentials.email
@ -64,11 +64,11 @@ export class AuthService {
} catch (error) {
if (error instanceof ConflictException) {
throw new ConflictException(
'Diese E-Mail-Adresse ist bereits registriert.'
'User already exists. Please try to login instead.'
);
} else {
throw new HttpException(
'Fehler bei der Registrierung',
'Error while signing up',
HttpStatus.INTERNAL_SERVER_ERROR
);
}
@ -99,22 +99,49 @@ export class AuthService {
} catch (error) {
if (error instanceof ForbiddenException) {
throw new ForbiddenException(
'Die eingebenen Daten sind nicht korrekt. Bitte versuchen Sie es erneut.'
'E-Mail address or password is incorrect. Please try again.'
);
} else {
throw new HttpException(
'Fehler beim Login',
'Error while validating user credentials',
HttpStatus.INTERNAL_SERVER_ERROR
);
}
}
}
public async checkAuthStatus(
sessionId: string,
userAgend: string
): Promise<SuccessDto> {
try {
const session =
await this.sessionService.findSessionBySessionId(sessionId);
if (!session) {
throw new ForbiddenException('Session not found');
}
const userAgendFromSession = JSON.parse(session.json).passport.user
.userAgent;
if (userAgendFromSession !== userAgend) {
throw new ForbiddenException('User-Agent does not match');
}
return { success: true };
} catch (error) {
throw new HttpException(
'Error while checking auth status',
HttpStatus.INTERNAL_SERVER_ERROR
);
}
}
public getLoginResponse(
user: LoginResponseDto & { userAgent: string }
): LoginResponseDto {
const { id, email }: LoginResponseDto = user;
const responseData: LoginResponseDto = { id, email };
user: SigninResponseDto & { userAgent: string }
): SigninResponseDto {
const { id, email }: SigninResponseDto = user;
const responseData: SigninResponseDto = { id, email };
return responseData;
}

View File

@ -3,7 +3,7 @@ import { PassportStrategy } from '@nestjs/passport';
import { Request } from 'express';
import { Strategy } from 'passport-local';
import { LoginResponseDto } from '../models/dto';
import { SigninResponseDto } from '../models/dto';
import { AuthService } from '../services/auth.service';
@Injectable()
@ -20,7 +20,7 @@ export class LocalStrategy extends PassportStrategy(Strategy) {
request: Request,
email: string,
password: string
): Promise<LoginResponseDto & { userAgent: string }> {
): Promise<SigninResponseDto & { userAgent: string }> {
const user = await this.authService.validateUser(email, password);
if (!user) {

View File

@ -1,2 +1,3 @@
export * from './utils/index';
export * from './decorator/index';
export * from './models/index';

View File

@ -0,0 +1 @@
export * from './success.dto';

View File

@ -0,0 +1,11 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsBoolean } from 'class-validator';
export class SuccessDto {
@ApiProperty({
description: 'Success status',
type: Boolean,
})
@IsBoolean()
public success: boolean;
}

View File

@ -0,0 +1 @@
export * from './dto/index';