Refactored Auth with Sessions #12
|
@ -15,10 +15,7 @@ export class UserCredentials {
|
|||
public email: string;
|
||||
|
||||
@Column()
|
||||
public hash: string;
|
||||
|
||||
@Column({ nullable: true })
|
||||
public refreshToken?: string;
|
||||
public hashedPassword: string;
|
||||
|
||||
@CreateDateColumn()
|
||||
public createdAt: Date;
|
||||
|
|
|
@ -18,9 +18,9 @@ export class UserData {
|
|||
@Column({ default: false })
|
||||
public isEmailConfirmed: boolean;
|
||||
|
||||
@OneToOne(() => UserCredentials)
|
||||
@JoinColumn({ name: 'userCredentialsId' })
|
||||
public user: UserCredentials;
|
||||
@OneToOne(() => UserCredentials, { eager: true }) // eager: true lädt UserCredentials automatisch, wenn Sie UserData laden
|
||||
@JoinColumn() // Diese Dekoration sagt TypeORM, welche Spalte der Fremdschlüssel ist
|
||||
public userCredentials: UserCredentials;
|
||||
|
||||
@CreateDateColumn()
|
||||
public createdAt: Date;
|
||||
|
|
|
@ -19,7 +19,7 @@ export class AuthController {
|
|||
@HttpCode(HttpStatus.CREATED)
|
||||
public async signup(
|
||||
@Body() userCredentials: UserCredentialsDto
|
||||
): Promise<LoginResponseDto> {
|
||||
): Promise<{ success: boolean }> {
|
||||
return this.authService.signup(userCredentials);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,9 +12,9 @@ export class UserCredentialsRepository {
|
|||
|
||||
public async createUser(
|
||||
email: string,
|
||||
hash: string
|
||||
hashedPassword: string
|
||||
): Promise<UserCredentials> {
|
||||
const user = this.repository.create({ email, hash });
|
||||
const user = this.repository.create({ email, hashedPassword });
|
||||
|
||||
return this.repository.save(user);
|
||||
}
|
||||
|
@ -31,12 +31,12 @@ export class UserCredentialsRepository {
|
|||
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 });
|
||||
// public async updateUserRefreshToken(
|
||||
// userId: string,
|
||||
// refreshToken: string | null
|
||||
// ): Promise<number> {
|
||||
// const result = await this.repository.update(userId, { refreshToken });
|
||||
|
||||
return result.affected ?? 0;
|
||||
}
|
||||
// return result.affected ?? 0;
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import {
|
||||
ConflictException,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
Injectable,
|
||||
} from '@nestjs/common';
|
||||
import { EncryptionService } from 'src/shared';
|
||||
|
||||
import { PasswordConfirmationMailService } from '../../sendgrid-module/services/password-confirmation.mail.service';
|
||||
|
@ -23,29 +28,52 @@ export class AuthService {
|
|||
|
||||
public async signup(
|
||||
userCredentials: UserCredentialsDto
|
||||
): Promise<LoginResponseDto> {
|
||||
const passwordHashed = await EncryptionService.hashData(
|
||||
userCredentials.password
|
||||
);
|
||||
|
||||
const user = await this.userCredentialsRepository.createUser(
|
||||
userCredentials.email,
|
||||
passwordHashed
|
||||
);
|
||||
|
||||
await this.userDataRepository.createInitialUserData(user);
|
||||
|
||||
const token =
|
||||
await this.emailVerificationService.generateEmailVerificationToken(
|
||||
user.id
|
||||
): Promise<{ success: boolean }> {
|
||||
try {
|
||||
const existingUser = await this.userCredentialsRepository.findUserByEmail(
|
||||
userCredentials.email
|
||||
);
|
||||
|
||||
await this.passwordConfirmationMailService.sendPasswordConfirmationMail(
|
||||
user.email,
|
||||
token
|
||||
);
|
||||
if (existingUser) {
|
||||
throw new ConflictException('User already exists');
|
||||
}
|
||||
|
||||
//return this.generateAndPersistTokens(user.id, user.email);
|
||||
const passwordHashed = await EncryptionService.hashData(
|
||||
userCredentials.password
|
||||
);
|
||||
|
||||
const user = await this.userCredentialsRepository.createUser(
|
||||
userCredentials.email,
|
||||
passwordHashed
|
||||
);
|
||||
|
||||
await this.userDataRepository.createInitialUserData(user);
|
||||
|
||||
const token =
|
||||
await this.emailVerificationService.generateEmailVerificationToken(
|
||||
user.id
|
||||
);
|
||||
|
||||
await this.passwordConfirmationMailService.sendPasswordConfirmationMail(
|
||||
user.email,
|
||||
token
|
||||
);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
};
|
||||
} catch (error) {
|
||||
if (error instanceof ConflictException) {
|
||||
throw new ConflictException(
|
||||
'Diese E-Mail-Adresse ist bereits registriert.'
|
||||
);
|
||||
} else {
|
||||
throw new HttpException(
|
||||
'Fehler bei der Registrierung',
|
||||
HttpStatus.INTERNAL_SERVER_ERROR
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// public async signin(
|
||||
|
@ -129,25 +157,17 @@ export class AuthService {
|
|||
// return { access_token: newTokens.access_token };
|
||||
// }
|
||||
|
||||
// private async generateAndPersistTokens(
|
||||
// userId: string,
|
||||
// email: string,
|
||||
// updateRefreshToken: boolean = false
|
||||
// ): Promise<LoginResponseDto> {
|
||||
// const tokens = await this.tokenManagementService.generateTokens(
|
||||
// userId,
|
||||
// email
|
||||
// );
|
||||
private async generateAndPersistTokens(
|
||||
userId: string,
|
||||
email: string
|
||||
): Promise<LoginResponseDto> {
|
||||
const tokens = await this.tokenManagementService.generateTokens(
|
||||
userId,
|
||||
email
|
||||
);
|
||||
|
||||
// if (updateRefreshToken) {
|
||||
// await this.userCredentialsRepository.updateUserRefreshToken(
|
||||
// userId,
|
||||
// tokens.refresh_token
|
||||
// );
|
||||
// }
|
||||
|
||||
// return { access_token: tokens.access_token, email: email, userId: userId };
|
||||
// }
|
||||
return { access_token: tokens.access_token, email: email, userId: userId };
|
||||
}
|
||||
|
||||
// private async validateRefreshToken(userId: string): Promise<TokenPayload> {
|
||||
// const user = await this.userCredentialsRepository.findUserById(userId);
|
||||
|
|
|
@ -2,14 +2,13 @@ import { Injectable } from '@nestjs/common';
|
|||
import { ConfigService } from '@nestjs/config';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
|
||||
import { TokenPayload, Tokens } from '../models/types';
|
||||
import { AccessTokenDto } from '../models/dto';
|
||||
import { TokenPayload } from '../models/types';
|
||||
|
||||
@Injectable()
|
||||
export class TokenManagementService {
|
||||
private readonly ACCESS_TOKEN_EXPIRY: string;
|
||||
private readonly REFRESH_TOKEN_EXPIRY: string;
|
||||
private readonly JWT_SECRET_AT: string;
|
||||
private readonly JWT_SECRET_RT: string;
|
||||
|
||||
public constructor(
|
||||
private readonly jwt: JwtService,
|
||||
|
@ -18,23 +17,21 @@ export class TokenManagementService {
|
|||
this.ACCESS_TOKEN_EXPIRY = this.configService.get<string>(
|
||||
'ACCESS_TOKEN_EXPIRY'
|
||||
);
|
||||
this.REFRESH_TOKEN_EXPIRY = this.configService.get<string>(
|
||||
'REFRESH_TOKEN_EXPIRY'
|
||||
);
|
||||
this.JWT_SECRET_AT = this.configService.get<string>('JWT_SECRET_AT');
|
||||
this.JWT_SECRET_RT = this.configService.get<string>('JWT_SECRET_RT');
|
||||
}
|
||||
|
||||
public async generateTokens(userId: string, email: string): Promise<Tokens> {
|
||||
public async generateTokens(
|
||||
userId: string,
|
||||
email: string
|
||||
): Promise<AccessTokenDto> {
|
||||
const access_token: string = await this.createAccessToken(userId, email);
|
||||
const refresh_token: string = await this.createRefreshToken(userId, email);
|
||||
|
||||
return { access_token, refresh_token };
|
||||
return { access_token };
|
||||
}
|
||||
|
||||
public async verifyRefreshToken(token: string): Promise<TokenPayload> {
|
||||
return this.jwt.verifyAsync(token, {
|
||||
secret: this.JWT_SECRET_RT,
|
||||
secret: this.JWT_SECRET_AT,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -50,17 +47,4 @@ export class TokenManagementService {
|
|||
}
|
||||
);
|
||||
}
|
||||
|
||||
private async createRefreshToken(
|
||||
userId: string,
|
||||
email: string
|
||||
): Promise<string> {
|
||||
return this.jwt.signAsync(
|
||||
{ sub: userId, email },
|
||||
{
|
||||
expiresIn: this.REFRESH_TOKEN_EXPIRY,
|
||||
secret: this.JWT_SECRET_RT,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,16 +15,16 @@ export class UserDataRepository {
|
|||
): Promise<UserData> {
|
||||
const userData = new UserData();
|
||||
|
||||
userData.user = userCredentials;
|
||||
userData.userCredentials = userCredentials;
|
||||
userData.isEmailConfirmed = false;
|
||||
|
||||
return this.repository.save(userData);
|
||||
}
|
||||
|
||||
public async updateEmailVerificationStatus(userId: string): Promise<void> {
|
||||
await this.repository.update(
|
||||
{ user: { id: userId } },
|
||||
{ isEmailConfirmed: true }
|
||||
);
|
||||
}
|
||||
// public async updateEmailVerificationStatus(userId: string): Promise<void> {
|
||||
// await this.repository.update(
|
||||
// { user: { id: userId } },
|
||||
// { isEmailConfirmed: true }
|
||||
// );
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -42,9 +42,9 @@ export class EmailVerificationService {
|
|||
await this.deleteEmailVerificationToken(tokenToVerify);
|
||||
|
||||
if (emailVerification && emailVerification.user) {
|
||||
await this.userDataRepository.updateEmailVerificationStatus(
|
||||
emailVerification.user.id
|
||||
);
|
||||
// await this.userDataRepository.updateEmailVerificationStatus(
|
||||
// emailVerification.user.id
|
||||
// );
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
|
Loading…
Reference in New Issue