Refactored Auth with Sessions #12
|
@ -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']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
export * from './user-credentials.dto';
|
||||
export * from './login-response.dto';
|
||||
export * from './signin-response.dto';
|
||||
|
|
|
@ -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',
|
|
@ -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;
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
export * from './utils/index';
|
||||
export * from './decorator/index';
|
||||
export * from './models/index';
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export * from './success.dto';
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export * from './dto/index';
|
Loading…
Reference in New Issue