chore(codebase): full cleanup pass
This commit is contained in:
@@ -3,12 +3,12 @@
|
||||
public record JwtOptions
|
||||
{
|
||||
public const string SectionName = "Authentication:Jwt";
|
||||
|
||||
|
||||
public required TimeSpan Lifetime { get; init; }
|
||||
public required string Issuer { get; init; }
|
||||
public required string Audience { get; init; }
|
||||
public required string Key { get; init; }
|
||||
|
||||
|
||||
public TimeSpan RefreshTokenLifetime { get; init; }
|
||||
public bool RefreshTokenRequireRotation { get; init; }
|
||||
}
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
|
||||
namespace Hutopy.Modules.Identity.Data
|
||||
{
|
||||
public class IdentityDbContext(
|
||||
DbContextOptions<IdentityDbContext> options)
|
||||
: IdentityDbContext<User, Role, Guid>(options)
|
||||
{
|
||||
public const string SchemaName = "Identity";
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder
|
||||
modelBuilder)
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
|
||||
modelBuilder.HasDefaultSchema(SchemaName);
|
||||
}
|
||||
namespace Hutopy.Modules.Identity.Data;
|
||||
|
||||
public class IdentityDbContext(
|
||||
DbContextOptions<IdentityDbContext> options)
|
||||
: IdentityDbContext<User, Role, Guid>(options)
|
||||
{
|
||||
public const string SchemaName = "Identity";
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder
|
||||
modelBuilder)
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
|
||||
modelBuilder.HasDefaultSchema(SchemaName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,19 +10,22 @@ public class IdentityService(
|
||||
{
|
||||
public async Task<UserModel?> GetCurrentUserAsync()
|
||||
{
|
||||
var currentUserId = contextAccessor.HttpContext?.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
||||
string? currentUserId = contextAccessor.HttpContext?.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
||||
if (string.IsNullOrEmpty(currentUserId))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
UserModel? ret;
|
||||
var user = await userManager.FindByIdAsync(currentUserId);
|
||||
User? user = await userManager.FindByIdAsync(currentUserId);
|
||||
|
||||
if (user == null) ret = null;
|
||||
if (user == null)
|
||||
{
|
||||
ret = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
var userModel = new UserModel
|
||||
UserModel userModel = new()
|
||||
{
|
||||
Id = user.Id,
|
||||
Username = user.UserName ?? string.Empty,
|
||||
@@ -44,17 +47,22 @@ public class IdentityService(
|
||||
|
||||
public async Task<IList<string>> GetCurrentUserRolesAsync()
|
||||
{
|
||||
var currentUserModel = await GetCurrentUserAsync();
|
||||
UserModel? currentUserModel = await GetCurrentUserAsync();
|
||||
|
||||
if (currentUserModel is null) return [];
|
||||
|
||||
var currentUser = await userManager.FindByIdAsync(currentUserModel.Id.ToString());
|
||||
if (currentUserModel is null)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
if (currentUser is null) return [];
|
||||
User? currentUser = await userManager.FindByIdAsync(currentUserModel.Id.ToString());
|
||||
|
||||
var userRoles = await userManager.GetRolesAsync(currentUser);
|
||||
if (currentUser is null)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
IList<string> userRoles = await userManager.GetRolesAsync(currentUser);
|
||||
|
||||
return userRoles;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,4 +17,3 @@ public class User : IdentityUser<Guid>
|
||||
public DateTime RefreshTokenExpiryTime { get; set; }
|
||||
public string Fullname => $"{Lastname}, {Firstname}";
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Hutopy.Infrastructure.Security;
|
||||
using Hutopy.Modules.Identity.Data;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace Hutopy.Modules.Identity.Handlers;
|
||||
|
||||
@@ -22,7 +23,7 @@ public class ChangeAddressHandler(
|
||||
ChangeAddressRequest request,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var user = await userManager.FindByIdAsync(HttpContext.User.GetUserId().ToString());
|
||||
User? user = await userManager.FindByIdAsync(HttpContext.User.GetUserId().ToString());
|
||||
|
||||
if (user is null)
|
||||
{
|
||||
@@ -32,11 +33,15 @@ public class ChangeAddressHandler(
|
||||
|
||||
user.Address = request.Address;
|
||||
|
||||
var result = await userManager.UpdateAsync(user);
|
||||
IdentityResult result = await userManager.UpdateAsync(user);
|
||||
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await SendOkAsync(ct);
|
||||
}
|
||||
else
|
||||
{
|
||||
await SendUnauthorizedAsync(ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Hutopy.Infrastructure.Security;
|
||||
using Hutopy.Modules.Identity.Data;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace Hutopy.Modules.Identity.Handlers;
|
||||
|
||||
@@ -22,7 +23,7 @@ public class ChangeAliasHandler(
|
||||
ChangeAliasRequest request,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var user = await userManager.FindByIdAsync(HttpContext.User.GetUserId().ToString());
|
||||
User? user = await userManager.FindByIdAsync(HttpContext.User.GetUserId().ToString());
|
||||
|
||||
if (user is null)
|
||||
{
|
||||
@@ -32,11 +33,15 @@ public class ChangeAliasHandler(
|
||||
|
||||
user.Alias = request.Alias;
|
||||
|
||||
var result = await userManager.UpdateAsync(user);
|
||||
IdentityResult result = await userManager.UpdateAsync(user);
|
||||
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await SendOkAsync(ct);
|
||||
}
|
||||
else
|
||||
{
|
||||
await SendUnauthorizedAsync(ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Hutopy.Infrastructure.Security;
|
||||
using Hutopy.Modules.Identity.Data;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace Hutopy.Modules.Identity.Handlers;
|
||||
|
||||
@@ -22,7 +23,7 @@ public class ChangeBirthDateHandler(
|
||||
ChangeBirthDateRequest request,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var user = await userManager.FindByIdAsync(HttpContext.User.GetUserId().ToString());
|
||||
User? user = await userManager.FindByIdAsync(HttpContext.User.GetUserId().ToString());
|
||||
|
||||
if (user is null)
|
||||
{
|
||||
@@ -32,11 +33,15 @@ public class ChangeBirthDateHandler(
|
||||
|
||||
user.BirthDate = request.BirthDate;
|
||||
|
||||
var result = await userManager.UpdateAsync(user);
|
||||
IdentityResult result = await userManager.UpdateAsync(user);
|
||||
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await SendOkAsync(ct);
|
||||
}
|
||||
else
|
||||
{
|
||||
await SendUnauthorizedAsync(ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Hutopy.Infrastructure.Security;
|
||||
using Hutopy.Modules.Identity.Data;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace Hutopy.Modules.Identity.Handlers;
|
||||
|
||||
@@ -22,7 +23,7 @@ public class ChangeEmailHandler(
|
||||
ChangeEmailRequest request,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var user = await userManager.FindByIdAsync(HttpContext.User.GetUserId().ToString());
|
||||
User? user = await userManager.FindByIdAsync(HttpContext.User.GetUserId().ToString());
|
||||
|
||||
if (user is null)
|
||||
{
|
||||
@@ -33,11 +34,15 @@ public class ChangeEmailHandler(
|
||||
user.Email = request.Email;
|
||||
|
||||
// TODO: check to see if identity resets the `email confirmed` flag - @jonathan
|
||||
var result = await userManager.UpdateAsync(user);
|
||||
IdentityResult result = await userManager.UpdateAsync(user);
|
||||
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await SendOkAsync(ct);
|
||||
}
|
||||
else
|
||||
{
|
||||
await SendUnauthorizedAsync(ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Hutopy.Infrastructure.Security;
|
||||
using Hutopy.Modules.Identity.Data;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace Hutopy.Modules.Identity.Handlers;
|
||||
|
||||
@@ -23,7 +24,7 @@ public class ChangeFullnameHandler(
|
||||
ChangeFullnameRequest request,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var user = await userManager.FindByIdAsync(HttpContext.User.GetUserId().ToString());
|
||||
User? user = await userManager.FindByIdAsync(HttpContext.User.GetUserId().ToString());
|
||||
|
||||
if (user is null)
|
||||
{
|
||||
@@ -34,11 +35,15 @@ public class ChangeFullnameHandler(
|
||||
user.Firstname = request.Firstname;
|
||||
user.Lastname = request.Lastname;
|
||||
|
||||
var result = await userManager.UpdateAsync(user);
|
||||
IdentityResult result = await userManager.UpdateAsync(user);
|
||||
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await SendOkAsync(ct);
|
||||
}
|
||||
else
|
||||
{
|
||||
await SendUnauthorizedAsync(ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Hutopy.Infrastructure.Security;
|
||||
using Hutopy.Modules.Identity.Data;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace Hutopy.Modules.Identity.Handlers;
|
||||
|
||||
@@ -22,7 +23,7 @@ public class ChangePhoneHandler(
|
||||
ChangePhoneRequest request,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var user = await userManager.FindByIdAsync(HttpContext.User.GetUserId().ToString());
|
||||
User? user = await userManager.FindByIdAsync(HttpContext.User.GetUserId().ToString());
|
||||
|
||||
if (user is null)
|
||||
{
|
||||
@@ -33,11 +34,15 @@ public class ChangePhoneHandler(
|
||||
user.PhoneNumber = request.PhoneNumber;
|
||||
// TODO: check to see if identity resets the `phone confirmed` flag - @jonathan
|
||||
|
||||
var result = await userManager.UpdateAsync(user);
|
||||
IdentityResult result = await userManager.UpdateAsync(user);
|
||||
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await SendOkAsync(ct);
|
||||
}
|
||||
else
|
||||
{
|
||||
await SendUnauthorizedAsync(ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Hutopy.Infrastructure.BlobStorage.Contracts;
|
||||
using Hutopy.Infrastructure.Security;
|
||||
using Hutopy.Modules.Identity.Data;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace Hutopy.Modules.Identity.Handlers;
|
||||
|
||||
@@ -40,7 +41,7 @@ public class ChangePortraitHandler(
|
||||
ChangePortraitRequest request,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var user = await userManager.FindByIdAsync(HttpContext.User.GetUserId().ToString());
|
||||
User? user = await userManager.FindByIdAsync(HttpContext.User.GetUserId().ToString());
|
||||
|
||||
if (user is null)
|
||||
{
|
||||
@@ -48,7 +49,7 @@ public class ChangePortraitHandler(
|
||||
return;
|
||||
}
|
||||
|
||||
var blobUrl = await blobStorage.UploadFileAsync(
|
||||
string blobUrl = await blobStorage.UploadFileAsync(
|
||||
ContainerNames.Users,
|
||||
$"{user.Id}/{SubDirectoryNames.Profile}/{CommonFileNames.ProfilePicture}",
|
||||
request.File.OpenReadStream(),
|
||||
@@ -57,7 +58,7 @@ public class ChangePortraitHandler(
|
||||
|
||||
user.PortraitUrl = blobUrl;
|
||||
|
||||
var result = await userManager.UpdateAsync(user);
|
||||
IdentityResult result = await userManager.UpdateAsync(user);
|
||||
|
||||
if (result.Succeeded)
|
||||
{
|
||||
|
||||
@@ -17,16 +17,16 @@ public class GetCurrentUserQueryHandler(
|
||||
public override async Task HandleAsync(
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var userModel = await identityService.GetCurrentUserAsync();
|
||||
UserModel? userModel = await identityService.GetCurrentUserAsync();
|
||||
|
||||
if (userModel is null)
|
||||
{
|
||||
await SendNotFoundAsync(cancellationToken);
|
||||
return;
|
||||
}
|
||||
|
||||
var roles = await identityService.GetCurrentUserRolesAsync();
|
||||
|
||||
|
||||
IList<string> roles = await identityService.GetCurrentUserRolesAsync();
|
||||
|
||||
await SendOkAsync(
|
||||
new UserDto
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Hutopy.Infrastructure.BlobStorage.Contracts;
|
||||
using Hutopy.Modules.Identity.Data;
|
||||
using Hutopy.Modules.Identity.Models;
|
||||
|
||||
namespace Hutopy.Modules.Identity.Handlers;
|
||||
|
||||
@@ -19,7 +20,7 @@ public class GetCurrentUserPortraitHandler(
|
||||
public override async Task HandleAsync(
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var identityUser = await identityService.GetCurrentUserAsync();
|
||||
UserModel? identityUser = await identityService.GetCurrentUserAsync();
|
||||
|
||||
if (identityUser is null)
|
||||
{
|
||||
@@ -27,7 +28,7 @@ public class GetCurrentUserPortraitHandler(
|
||||
return;
|
||||
}
|
||||
|
||||
var stream = await blobStorage.DownloadFileAsync(
|
||||
MemoryStream stream = await blobStorage.DownloadFileAsync(
|
||||
ContainerNames.Users,
|
||||
$"{identityUser.Id.ToString()}/{SubDirectoryNames.Profile}/{CommonFileNames.ProfilePicture}",
|
||||
cancellationToken);
|
||||
|
||||
@@ -32,7 +32,7 @@ public class RefreshTokenHandler(
|
||||
CancellationToken ct)
|
||||
{
|
||||
// Find the user using the refresh token
|
||||
var user = await userManager.Users
|
||||
User? user = await userManager.Users
|
||||
.FirstOrDefaultAsync(u => u.RefreshToken == request.RefreshToken, ct);
|
||||
|
||||
if (user == null || user.RefreshTokenExpiryTime <= DateTime.UtcNow)
|
||||
@@ -52,20 +52,20 @@ public class RefreshTokenHandler(
|
||||
await userManager.UpdateAsync(user);
|
||||
|
||||
// Generate a new access token
|
||||
var accessToken = JwtTokenHelper.GenerateJwtToken(
|
||||
expiresIn: jwtOptions.Value.Lifetime,
|
||||
issuer: jwtOptions.Value.Issuer,
|
||||
audience: jwtOptions.Value.Audience,
|
||||
key: jwtOptions.Value.Key,
|
||||
userId: user.Id.ToString(),
|
||||
email: user.Email ?? string.Empty,
|
||||
alias: user.Alias,
|
||||
firstname: user.Firstname ?? string.Empty,
|
||||
lastname: user.Lastname ?? string.Empty,
|
||||
portraitUrl: user.PortraitUrl);
|
||||
string accessToken = JwtTokenHelper.GenerateJwtToken(
|
||||
jwtOptions.Value.Lifetime,
|
||||
jwtOptions.Value.Issuer,
|
||||
jwtOptions.Value.Audience,
|
||||
jwtOptions.Value.Key,
|
||||
user.Id.ToString(),
|
||||
user.Email ?? string.Empty,
|
||||
user.Alias,
|
||||
user.Firstname ?? string.Empty,
|
||||
user.Lastname ?? string.Empty,
|
||||
user.PortraitUrl);
|
||||
|
||||
await SendOkAsync(
|
||||
new RefreshTokenResponse(accessToken, user.RefreshToken),
|
||||
cancellation: ct);
|
||||
ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Hutopy.Modules.Identity.Data;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace Hutopy.Modules.Identity.Handlers;
|
||||
|
||||
@@ -25,7 +26,7 @@ public class ResetPasswordHandler(
|
||||
CancellationToken ct)
|
||||
{
|
||||
// Find user by email
|
||||
var user = await userManager.FindByEmailAsync(request.Email);
|
||||
User? user = await userManager.FindByEmailAsync(request.Email);
|
||||
if (user is null)
|
||||
{
|
||||
await SendStringAsync(
|
||||
@@ -36,7 +37,7 @@ public class ResetPasswordHandler(
|
||||
}
|
||||
|
||||
// Reset password with token
|
||||
var result = await userManager.ResetPasswordAsync(
|
||||
IdentityResult result = await userManager.ResetPasswordAsync(
|
||||
user,
|
||||
request.Token,
|
||||
request.NewPassword);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Hutopy.Infrastructure.Security;
|
||||
using Hutopy.Modules.Identity.Data;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace Hutopy.Modules.Identity.Handlers;
|
||||
|
||||
@@ -23,19 +24,19 @@ public class SetPasswordHandler(
|
||||
CancellationToken ct)
|
||||
{
|
||||
// Get current user id from claims
|
||||
var userId = User.GetUserId().ToString();
|
||||
|
||||
string userId = User.GetUserId().ToString();
|
||||
|
||||
// Get user from database
|
||||
var user = await userManager.FindByIdAsync(userId);
|
||||
User? user = await userManager.FindByIdAsync(userId);
|
||||
if (user is null)
|
||||
{
|
||||
await SendForbiddenAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
var resetToken = await userManager.GeneratePasswordResetTokenAsync(user);
|
||||
var result = await userManager.ResetPasswordAsync(user, resetToken, request.NewPassword);
|
||||
|
||||
string resetToken = await userManager.GeneratePasswordResetTokenAsync(user);
|
||||
IdentityResult result = await userManager.ResetPasswordAsync(user, resetToken, request.NewPassword);
|
||||
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
await SendStringAsync(
|
||||
@@ -44,7 +45,7 @@ public class SetPasswordHandler(
|
||||
cancellation: ct);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
await SendOkAsync(ct);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
namespace Hutopy.Modules.Identity.Models;
|
||||
|
||||
public class Result(
|
||||
bool succeeded,
|
||||
bool succeeded,
|
||||
IEnumerable<string> errors)
|
||||
{
|
||||
public bool Succeeded { get; init; } = succeeded;
|
||||
public string[] Errors { get; init; } = errors.ToArray();
|
||||
|
||||
|
||||
public static Result Success()
|
||||
{
|
||||
return new Result(true, Array.Empty<string>());
|
||||
@@ -20,18 +20,18 @@ public class Result(
|
||||
|
||||
public class Result<T>(
|
||||
T? value,
|
||||
bool succeeded,
|
||||
bool succeeded,
|
||||
IEnumerable<string> errors)
|
||||
{
|
||||
public bool Succeeded { get; init; } = succeeded;
|
||||
public string[] Errors { get; init; } = errors.ToArray();
|
||||
public T? Value { get; set; } = value;
|
||||
|
||||
|
||||
public T GetValueOrDefault()
|
||||
{
|
||||
return Value ?? default(T)!;
|
||||
}
|
||||
|
||||
|
||||
public string GetErrorsAsString()
|
||||
{
|
||||
return Errors.Length == 0 ? string.Empty : string.Join(", ", Errors);
|
||||
|
||||
@@ -9,7 +9,7 @@ public sealed class UserLookup(
|
||||
{
|
||||
public async Task<UserReference?> GetUserAsync(Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var user = await userManager.FindByIdAsync(userId.ToString());
|
||||
User? user = await userManager.FindByIdAsync(userId.ToString());
|
||||
|
||||
return user is null
|
||||
? null
|
||||
|
||||
Reference in New Issue
Block a user