Co-authored-by: Julien Martin <julien.martin@ptits-pas.fr> Co-committed-by: Julien Martin <julien.martin@ptits-pas.fr>
This commit is contained in:
parent
c5028c3b22
commit
95d1c3741b
@ -1,10 +1,11 @@
|
|||||||
import { Body, Controller, Get, Post, Req, UnauthorizedException, UseGuards } from '@nestjs/common';
|
import { Body, Controller, Get, Post, Req, UnauthorizedException, BadRequestException, UseGuards } from '@nestjs/common';
|
||||||
import { LoginDto } from './dto/login.dto';
|
import { LoginDto } from './dto/login.dto';
|
||||||
import { AuthService } from './auth.service';
|
import { AuthService } from './auth.service';
|
||||||
import { Public } from 'src/common/decorators/public.decorator';
|
import { Public } from 'src/common/decorators/public.decorator';
|
||||||
import { RegisterDto } from './dto/register.dto';
|
import { RegisterDto } from './dto/register.dto';
|
||||||
import { RegisterParentDto } from './dto/register-parent.dto';
|
import { RegisterParentDto } from './dto/register-parent.dto';
|
||||||
import { RegisterParentCompletDto } from './dto/register-parent-complet.dto';
|
import { RegisterParentCompletDto } from './dto/register-parent-complet.dto';
|
||||||
|
import { ChangePasswordRequiredDto } from './dto/change-password.dto';
|
||||||
import { ApiBearerAuth, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
import { ApiBearerAuth, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
||||||
import { AuthGuard } from 'src/common/guards/auth.guard';
|
import { AuthGuard } from 'src/common/guards/auth.guard';
|
||||||
import type { Request } from 'express';
|
import type { Request } from 'express';
|
||||||
@ -97,5 +98,31 @@ export class AuthController {
|
|||||||
logout(@User() currentUser: Users) {
|
logout(@User() currentUser: Users) {
|
||||||
return this.authService.logout(currentUser.id);
|
return this.authService.logout(currentUser.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Post('change-password-required')
|
||||||
|
@UseGuards(AuthGuard)
|
||||||
|
@ApiBearerAuth('access-token')
|
||||||
|
@ApiOperation({
|
||||||
|
summary: 'Changement de mot de passe obligatoire',
|
||||||
|
description: 'Permet de changer le mot de passe lors de la première connexion (flag changement_mdp_obligatoire)'
|
||||||
|
})
|
||||||
|
@ApiResponse({ status: 200, description: 'Mot de passe changé avec succès' })
|
||||||
|
@ApiResponse({ status: 400, description: 'Mot de passe actuel incorrect ou confirmation non correspondante' })
|
||||||
|
@ApiResponse({ status: 403, description: 'Changement de mot de passe non requis pour cet utilisateur' })
|
||||||
|
async changePasswordRequired(
|
||||||
|
@User() currentUser: Users,
|
||||||
|
@Body() dto: ChangePasswordRequiredDto,
|
||||||
|
) {
|
||||||
|
// Vérifier que les mots de passe correspondent
|
||||||
|
if (dto.nouveau_mot_de_passe !== dto.confirmation_mot_de_passe) {
|
||||||
|
throw new BadRequestException('Les mots de passe ne correspondent pas');
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.authService.changePasswordRequired(
|
||||||
|
currentUser.id,
|
||||||
|
dto.mot_de_passe_actuel,
|
||||||
|
dto.nouveau_mot_de_passe,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -455,6 +455,60 @@ export class AuthService {
|
|||||||
return `/uploads/photos/${nomFichierUnique}`;
|
return `/uploads/photos/${nomFichierUnique}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changement de mot de passe obligatoire (première connexion)
|
||||||
|
*/
|
||||||
|
async changePasswordRequired(
|
||||||
|
userId: string,
|
||||||
|
motDePasseActuel: string,
|
||||||
|
nouveauMotDePasse: string,
|
||||||
|
) {
|
||||||
|
const user = await this.usersRepo.findOne({ where: { id: userId } });
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
throw new UnauthorizedException('Utilisateur introuvable');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vérifier que le changement est bien obligatoire
|
||||||
|
if (!user.changement_mdp_obligatoire) {
|
||||||
|
throw new BadRequestException(
|
||||||
|
'Le changement de mot de passe n\'est pas requis pour cet utilisateur',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vérifier que l'utilisateur a un mot de passe
|
||||||
|
if (!user.password) {
|
||||||
|
throw new BadRequestException('Compte non activé');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vérifier le mot de passe actuel
|
||||||
|
const motDePasseValide = await bcrypt.compare(motDePasseActuel, user.password);
|
||||||
|
if (!motDePasseValide) {
|
||||||
|
throw new BadRequestException('Mot de passe actuel incorrect');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vérifier que le nouveau mot de passe est différent de l'ancien
|
||||||
|
const memeMotDePasse = await bcrypt.compare(nouveauMotDePasse, user.password);
|
||||||
|
if (memeMotDePasse) {
|
||||||
|
throw new BadRequestException(
|
||||||
|
'Le nouveau mot de passe doit être différent de l\'ancien',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hasher et sauvegarder le nouveau mot de passe
|
||||||
|
const sel = await bcrypt.genSalt(12);
|
||||||
|
user.password = await bcrypt.hash(nouveauMotDePasse, sel);
|
||||||
|
user.changement_mdp_obligatoire = false;
|
||||||
|
user.modifie_le = new Date();
|
||||||
|
|
||||||
|
await this.usersRepo.save(user);
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: 'Mot de passe changé avec succès',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
async logout(userId: string) {
|
async logout(userId: string) {
|
||||||
return { success: true, message: 'Deconnexion'}
|
return { success: true, message: 'Deconnexion'}
|
||||||
}
|
}
|
||||||
|
|||||||
23
backend/src/routes/auth/dto/change-password.dto.ts
Normal file
23
backend/src/routes/auth/dto/change-password.dto.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString, MinLength, Matches } from 'class-validator';
|
||||||
|
|
||||||
|
export class ChangePasswordRequiredDto {
|
||||||
|
@ApiProperty({ description: 'Mot de passe actuel' })
|
||||||
|
@IsString()
|
||||||
|
mot_de_passe_actuel: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Nouveau mot de passe (min 8 caractères, 1 majuscule, 1 chiffre)',
|
||||||
|
minLength: 8
|
||||||
|
})
|
||||||
|
@IsString()
|
||||||
|
@MinLength(8, { message: 'Le mot de passe doit contenir au moins 8 caractères' })
|
||||||
|
@Matches(/^(?=.*[A-Z])(?=.*\d)/, {
|
||||||
|
message: 'Le mot de passe doit contenir au moins une majuscule et un chiffre'
|
||||||
|
})
|
||||||
|
nouveau_mot_de_passe: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Confirmation du nouveau mot de passe' })
|
||||||
|
@IsString()
|
||||||
|
confirmation_mot_de_passe: string;
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user