mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-10-15 01:54:43 +00:00
Decouple ITokenService from UserAccount entity
Token generation only ever needed the id/username, not the full UserAccount.
This commit is contained in:
@@ -92,13 +92,13 @@ public class RegisterUserHandlerTests
|
|||||||
);
|
);
|
||||||
|
|
||||||
_tokenServiceMock
|
_tokenServiceMock
|
||||||
.Setup(x => x.GenerateAccessToken(It.IsAny<UserAccount>()))
|
.Setup(x => x.GenerateAccessToken(It.IsAny<Guid>(), It.IsAny<string>()))
|
||||||
.Returns("access-token");
|
.Returns("access-token");
|
||||||
_tokenServiceMock
|
_tokenServiceMock
|
||||||
.Setup(x => x.GenerateRefreshToken(It.IsAny<UserAccount>()))
|
.Setup(x => x.GenerateRefreshToken(It.IsAny<Guid>(), It.IsAny<string>()))
|
||||||
.Returns("refresh-token");
|
.Returns("refresh-token");
|
||||||
_tokenServiceMock
|
_tokenServiceMock
|
||||||
.Setup(x => x.GenerateConfirmationToken(It.IsAny<UserAccount>()))
|
.Setup(x => x.GenerateConfirmationToken(It.IsAny<Guid>(), It.IsAny<string>()))
|
||||||
.Returns("confirmation-token");
|
.Returns("confirmation-token");
|
||||||
|
|
||||||
RegistrationPayload result = await _handler.Handle(command, CancellationToken.None);
|
RegistrationPayload result = await _handler.Handle(command, CancellationToken.None);
|
||||||
@@ -192,10 +192,10 @@ public class RegisterUserHandlerTests
|
|||||||
.ReturnsAsync(new UserAccount { UserAccountId = Guid.NewGuid() });
|
.ReturnsAsync(new UserAccount { UserAccountId = Guid.NewGuid() });
|
||||||
|
|
||||||
_tokenServiceMock
|
_tokenServiceMock
|
||||||
.Setup(x => x.GenerateAccessToken(It.IsAny<UserAccount>()))
|
.Setup(x => x.GenerateAccessToken(It.IsAny<Guid>(), It.IsAny<string>()))
|
||||||
.Returns("access-token");
|
.Returns("access-token");
|
||||||
_tokenServiceMock
|
_tokenServiceMock
|
||||||
.Setup(x => x.GenerateRefreshToken(It.IsAny<UserAccount>()))
|
.Setup(x => x.GenerateRefreshToken(It.IsAny<Guid>(), It.IsAny<string>()))
|
||||||
.Returns("refresh-token");
|
.Returns("refresh-token");
|
||||||
|
|
||||||
await _handler.Handle(command, CancellationToken.None);
|
await _handler.Handle(command, CancellationToken.None);
|
||||||
@@ -241,10 +241,10 @@ public class RegisterUserHandlerTests
|
|||||||
);
|
);
|
||||||
|
|
||||||
_tokenServiceMock
|
_tokenServiceMock
|
||||||
.Setup(x => x.GenerateAccessToken(It.IsAny<UserAccount>()))
|
.Setup(x => x.GenerateAccessToken(It.IsAny<Guid>(), It.IsAny<string>()))
|
||||||
.Returns("access-token");
|
.Returns("access-token");
|
||||||
_tokenServiceMock
|
_tokenServiceMock
|
||||||
.Setup(x => x.GenerateRefreshToken(It.IsAny<UserAccount>()))
|
.Setup(x => x.GenerateRefreshToken(It.IsAny<Guid>(), It.IsAny<string>()))
|
||||||
.Returns("refresh-token");
|
.Returns("refresh-token");
|
||||||
_mediatorMock
|
_mediatorMock
|
||||||
.Setup(x =>
|
.Setup(x =>
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public class ResendConfirmationEmailHandlerTests
|
|||||||
|
|
||||||
_authRepositoryMock.Setup(x => x.GetUserByIdAsync(userId)).ReturnsAsync(user);
|
_authRepositoryMock.Setup(x => x.GetUserByIdAsync(userId)).ReturnsAsync(user);
|
||||||
_authRepositoryMock.Setup(x => x.IsUserVerifiedAsync(userId)).ReturnsAsync(false);
|
_authRepositoryMock.Setup(x => x.IsUserVerifiedAsync(userId)).ReturnsAsync(false);
|
||||||
_tokenServiceMock.Setup(x => x.GenerateConfirmationToken(user)).Returns("fresh-token");
|
_tokenServiceMock.Setup(x => x.GenerateConfirmationToken(user.UserAccountId, user.Username)).Returns("fresh-token");
|
||||||
|
|
||||||
await _handler.Handle(new ResendConfirmationEmailCommand(userId), CancellationToken.None);
|
await _handler.Handle(new ResendConfirmationEmailCommand(userId), CancellationToken.None);
|
||||||
|
|
||||||
|
|||||||
@@ -61,10 +61,10 @@ public class LoginHandlerTests
|
|||||||
.Setup(x => x.Verify(It.IsAny<string>(), It.IsAny<string>()))
|
.Setup(x => x.Verify(It.IsAny<string>(), It.IsAny<string>()))
|
||||||
.Returns(true);
|
.Returns(true);
|
||||||
_tokenServiceMock
|
_tokenServiceMock
|
||||||
.Setup(x => x.GenerateAccessToken(It.IsAny<UserAccount>()))
|
.Setup(x => x.GenerateAccessToken(It.IsAny<Guid>(), It.IsAny<string>()))
|
||||||
.Returns("access-token");
|
.Returns("access-token");
|
||||||
_tokenServiceMock
|
_tokenServiceMock
|
||||||
.Setup(x => x.GenerateRefreshToken(It.IsAny<UserAccount>()))
|
.Setup(x => x.GenerateRefreshToken(It.IsAny<Guid>(), It.IsAny<string>()))
|
||||||
.Returns("refresh-token");
|
.Returns("refresh-token");
|
||||||
|
|
||||||
LoginPayload result = await _handler.Handle(
|
LoginPayload result = await _handler.Handle(
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ public class LoginHandler(
|
|||||||
if (!passwordInfrastructure.Verify(request.Password, activeCred.Hash))
|
if (!passwordInfrastructure.Verify(request.Password, activeCred.Hash))
|
||||||
throw new UnauthorizedException("Invalid username or password.");
|
throw new UnauthorizedException("Invalid username or password.");
|
||||||
|
|
||||||
string accessToken = tokenService.GenerateAccessToken(user);
|
string accessToken = tokenService.GenerateAccessToken(user.UserAccountId, user.Username);
|
||||||
string refreshToken = tokenService.GenerateRefreshToken(user);
|
string refreshToken = tokenService.GenerateRefreshToken(user.UserAccountId, user.Username);
|
||||||
|
|
||||||
return new LoginPayload(user.UserAccountId, user.Username, refreshToken, accessToken);
|
return new LoginPayload(user.UserAccountId, user.Username, refreshToken, accessToken);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,9 +48,18 @@ public class RegisterUserHandler(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
string accessToken = tokenService.GenerateAccessToken(createdUser);
|
string accessToken = tokenService.GenerateAccessToken(
|
||||||
string refreshToken = tokenService.GenerateRefreshToken(createdUser);
|
createdUser.UserAccountId,
|
||||||
string confirmationToken = tokenService.GenerateConfirmationToken(createdUser);
|
createdUser.Username
|
||||||
|
);
|
||||||
|
string refreshToken = tokenService.GenerateRefreshToken(
|
||||||
|
createdUser.UserAccountId,
|
||||||
|
createdUser.Username
|
||||||
|
);
|
||||||
|
string confirmationToken = tokenService.GenerateConfirmationToken(
|
||||||
|
createdUser.UserAccountId,
|
||||||
|
createdUser.Username
|
||||||
|
);
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(accessToken) || string.IsNullOrEmpty(refreshToken))
|
if (string.IsNullOrEmpty(accessToken) || string.IsNullOrEmpty(refreshToken))
|
||||||
return new RegistrationPayload(
|
return new RegistrationPayload(
|
||||||
|
|||||||
@@ -32,7 +32,10 @@ public class ResendConfirmationEmailHandler(
|
|||||||
if (await authRepository.IsUserVerifiedAsync(request.UserId))
|
if (await authRepository.IsUserVerifiedAsync(request.UserId))
|
||||||
return; // Already confirmed, no-op
|
return; // Already confirmed, no-op
|
||||||
|
|
||||||
string confirmationToken = tokenService.GenerateConfirmationToken(user);
|
string confirmationToken = tokenService.GenerateConfirmationToken(
|
||||||
|
user.UserAccountId,
|
||||||
|
user.Username
|
||||||
|
);
|
||||||
await mediator.Send(
|
await mediator.Send(
|
||||||
new SendResendConfirmationEmailCommand(user.FirstName, user.Email, confirmationToken),
|
new SendResendConfirmationEmailCommand(user.FirstName, user.Email, confirmationToken),
|
||||||
cancellationToken
|
cancellationToken
|
||||||
|
|||||||
@@ -48,19 +48,19 @@ public interface ITokenService
|
|||||||
/// Generates a signed access token for the given user, expiring after
|
/// Generates a signed access token for the given user, expiring after
|
||||||
/// <see cref="TokenServiceExpirationHours.AccessTokenHours" /> hours.
|
/// <see cref="TokenServiceExpirationHours.AccessTokenHours" /> hours.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string GenerateAccessToken(UserAccount user);
|
string GenerateAccessToken(Guid userId, string username);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates a signed refresh token for the given user, expiring after
|
/// Generates a signed refresh token for the given user, expiring after
|
||||||
/// <see cref="TokenServiceExpirationHours.RefreshTokenHours" /> hours.
|
/// <see cref="TokenServiceExpirationHours.RefreshTokenHours" /> hours.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string GenerateRefreshToken(UserAccount user);
|
string GenerateRefreshToken(Guid userId, string username);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates a signed confirmation token for the given user, expiring after
|
/// Generates a signed confirmation token for the given user, expiring after
|
||||||
/// <see cref="TokenServiceExpirationHours.ConfirmationTokenHours" /> hours.
|
/// <see cref="TokenServiceExpirationHours.ConfirmationTokenHours" /> hours.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string GenerateConfirmationToken(UserAccount user);
|
string GenerateConfirmationToken(Guid userId, string username);
|
||||||
|
|
||||||
|
|
||||||
/// <summary>Validates an access token's signature and expiration and extracts the caller's identity.</summary>
|
/// <summary>Validates an access token's signature and expiration and extracts the caller's identity.</summary>
|
||||||
|
|||||||
@@ -49,40 +49,30 @@ public class TokenService : ITokenService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string GenerateAccessToken(UserAccount user)
|
public string GenerateAccessToken(Guid userId, string username)
|
||||||
{
|
{
|
||||||
DateTime expiresAt = DateTime.UtcNow.AddHours(TokenServiceExpirationHours.AccessTokenHours);
|
DateTime expiresAt = DateTime.UtcNow.AddHours(TokenServiceExpirationHours.AccessTokenHours);
|
||||||
return _tokenInfrastructure.GenerateJwt(
|
return _tokenInfrastructure.GenerateJwt(userId, username, expiresAt, _accessTokenSecret);
|
||||||
user.UserAccountId,
|
|
||||||
user.Username,
|
|
||||||
expiresAt,
|
|
||||||
_accessTokenSecret
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string GenerateRefreshToken(UserAccount user)
|
public string GenerateRefreshToken(Guid userId, string username)
|
||||||
{
|
{
|
||||||
DateTime expiresAt = DateTime.UtcNow.AddHours(
|
DateTime expiresAt = DateTime.UtcNow.AddHours(
|
||||||
TokenServiceExpirationHours.RefreshTokenHours
|
TokenServiceExpirationHours.RefreshTokenHours
|
||||||
);
|
);
|
||||||
return _tokenInfrastructure.GenerateJwt(
|
return _tokenInfrastructure.GenerateJwt(userId, username, expiresAt, _refreshTokenSecret);
|
||||||
user.UserAccountId,
|
|
||||||
user.Username,
|
|
||||||
expiresAt,
|
|
||||||
_refreshTokenSecret
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string GenerateConfirmationToken(UserAccount user)
|
public string GenerateConfirmationToken(Guid userId, string username)
|
||||||
{
|
{
|
||||||
DateTime expiresAt = DateTime.UtcNow.AddHours(
|
DateTime expiresAt = DateTime.UtcNow.AddHours(
|
||||||
TokenServiceExpirationHours.ConfirmationTokenHours
|
TokenServiceExpirationHours.ConfirmationTokenHours
|
||||||
);
|
);
|
||||||
return _tokenInfrastructure.GenerateJwt(
|
return _tokenInfrastructure.GenerateJwt(
|
||||||
user.UserAccountId,
|
userId,
|
||||||
user.Username,
|
username,
|
||||||
expiresAt,
|
expiresAt,
|
||||||
_confirmationTokenSecret
|
_confirmationTokenSecret
|
||||||
);
|
);
|
||||||
@@ -114,8 +104,8 @@ public class TokenService : ITokenService
|
|||||||
if (user == null)
|
if (user == null)
|
||||||
throw new UnauthorizedException("User account not found");
|
throw new UnauthorizedException("User account not found");
|
||||||
|
|
||||||
string newAccess = GenerateAccessToken(user);
|
string newAccess = GenerateAccessToken(user.UserAccountId, user.Username);
|
||||||
string newRefresh = GenerateRefreshToken(user);
|
string newRefresh = GenerateRefreshToken(user.UserAccountId, user.Username);
|
||||||
|
|
||||||
return new RefreshTokenResult(user, newRefresh, newAccess);
|
return new RefreshTokenResult(user, newRefresh, newAccess);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user