Files
social-media/src/Infrastructure/Identity/IdentityService.cs
2024-09-07 10:55:46 -04:00

287 lines
8.9 KiB
C#

using Google.Apis.Oauth2.v2.Data;
using System.Security.Claims;
using Hutopy.Application.Common.Interfaces;
using Hutopy.Application.Common.Models;
using Hutopy.Infrastructure.Utils;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
namespace Hutopy.Infrastructure.Identity;
public class IdentityService(
ApplicationUserManager userManager,
SignInManager<ApplicationUser> signInManager,
IUserClaimsPrincipalFactory<ApplicationUser> userClaimsPrincipalFactory,
IAuthorizationService authorizationService,
IHttpContextAccessor contextAccessor,
IOptionsSnapshot<JwtOptions> jwtOptions
)
: IIdentityService
{
public async Task<string?> GetUserNameAsync(Guid userId)
{
var user = await userManager.FindByIdAsync(userId.ToString());
return user?.UserName;
}
public async Task<UserModel?> GetUserByUserNameAsync(string userName)
{
var user = await userManager.FindByNameAsync(userName);
if (user == null) return null;
return new()
{
Id = user.Id,
Username = user.UserName!,
PhoneNumber = user.PhoneNumber,
Email = user.Email,
Alias = user.Alias,
Firstname = user.Firstname,
Lastname = user.Lastname,
BirthDate = user.BirthDate,
Address = user.Address,
PortraitUrl = user.PortraitUrl
};
}
public async Task<Result<Guid>> CreateUserAsync(Userinfo userInfo)
{
var applicationUser = new ApplicationUser
{
UserName = userInfo.Name,
Email = userInfo.Email,
Firstname = userInfo.GivenName,
Lastname = userInfo.FamilyName
};
var password = Guid.NewGuid().ToString("N")[..32];
var identityResult = await userManager.CreateAsync(applicationUser, password);
var applicationResult = identityResult.ToApplicationResult();
var result = new Result<Guid>(applicationUser.Id, applicationResult.Succeeded, applicationResult.Errors);
return result;
}
public async Task<Result<Guid>> CreateUserAsync(string email, string userName, string firstName, string lastName,
string password)
{
var applicationUser = new ApplicationUser
{
UserName = userName, Email = email, Firstname = firstName, Lastname = lastName
};
var response = await userManager.CreateAsync(applicationUser, password);
if (!response.Succeeded)
{
throw new BadHttpRequestException(response.Errors.First().Description);
}
var result = new Result<Guid>(applicationUser.Id, response.Succeeded, response.ToApplicationResult().Errors);
return result;
}
public async Task<Result<Guid>> UpdateCurrentUserAsync(UserModel userModel)
{
var applicationUser = await userManager.FindByIdAsync(userModel.Id.ToString());
if (applicationUser is null) return Result<Guid>.Failure(Guid.Empty, new[] { "User not found." });
applicationUser.Id = userModel.Id;
applicationUser.Email = userModel.Email;
applicationUser.PhoneNumber = userModel.PhoneNumber;
applicationUser.Alias = userModel.Alias;
applicationUser.Firstname = userModel.Firstname;
applicationUser.Lastname = userModel.Lastname;
applicationUser.BirthDate = userModel.BirthDate;
applicationUser.Address = userModel.Address;
applicationUser.PortraitUrl = userModel.PortraitUrl;
var response = await userManager.UpdateAsync(applicationUser);
var applicationResult = response.ToApplicationResult();
var result = new Result<Guid>(
userModel.Id,
applicationResult.Succeeded,
applicationResult.Errors);
return result;
}
private static UserModel BuildModelFrom(ApplicationUser response)
{
var userModel = new UserModel
{
Id = response.Id,
Username = response.UserName ?? string.Empty,
PhoneNumber = response.PhoneNumber ?? string.Empty,
Email = response.Email ?? string.Empty,
PortraitUrl = response.PortraitUrl,
Alias = response.Alias,
Firstname = response.Firstname,
Lastname = response.Lastname,
BirthDate = response.BirthDate,
Address = response.Address,
};
return userModel;
}
public async Task<UserModel?> FindUserByIdAsync(string id)
{
var user = await userManager.FindByIdAsync(id);
if (user == null) return null;
var userModel = BuildModelFrom(user);
return userModel;
}
public async Task<UserModel?> FindUserByEmailAsync(string email)
{
var response = await userManager.FindByEmailAsync(email);
if (response == null) return null;
return BuildModelFrom(response);
}
public async Task<UserModel?> GetCurrentUserAsync()
{
var currentUserId = contextAccessor.HttpContext?.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
if (string.IsNullOrEmpty(currentUserId))
{
return null;
}
return await FindUserByIdAsync(currentUserId);
}
public async Task<Result> UpdateCurrentUserPortraitUrlAsync(string url)
{
var userModel = await GetCurrentUserAsync();
var applicationUser = await userManager.FindByIdAsync(userModel.Id.ToString());
if (applicationUser is null) return Result.Failure(["ApplicationUser not found."]);
applicationUser.PortraitUrl = url;
var response = await userManager.UpdateAsync(applicationUser);
return response.ToApplicationResult();
}
public async Task<bool> IsInRoleAsync(Guid userId, string role)
{
var user = await userManager.FindByIdAsync(userId.ToString());
return user != null && await userManager.IsInRoleAsync(user, role);
}
public async Task<bool> CurrentUserIsInRoleAsync(string role)
{
var currentUserModel = await GetCurrentUserAsync();
var currentUser = await userManager.FindByIdAsync(currentUserModel.Id.ToString());
return currentUser != null && await userManager.IsInRoleAsync(currentUser, role);
}
public async Task<bool> AuthorizeAsync(Guid userId, string policyName)
{
var user = await userManager.FindByIdAsync(userId.ToString());
if (user == null)
{
return false;
}
var principal = await userClaimsPrincipalFactory.CreateAsync(user);
var result = await authorizationService.AuthorizeAsync(principal, policyName);
return result.Succeeded;
}
public async Task<Result> DeleteUserAsync(string userId)
{
var user = await userManager.FindByIdAsync(userId);
return user != null ? await DeleteUserAsync(user) : Result.Success();
}
public async Task<Result> DeleteUserAsync(ApplicationUser user)
{
var result = await userManager.DeleteAsync(user);
return result.ToApplicationResult();
}
public async Task<Result> AddRoleAsync(string userId, string role)
{
var hasAdminAccess = await CurrentUserIsInRoleAsync("Administrator");
if (!hasAdminAccess) return Result.Failure(new[] { "Only administrator can assign new roles to a user." });
var user = await userManager.FindByIdAsync(userId);
if (user is null) return Result.Failure(new[] { "User not found." });
var result = await userManager.AddToRoleAsync(user, role);
return result.ToApplicationResult();
}
public async Task<IList<string>> GetCurrentUserRolesAsync()
{
var currentUserModel = await GetCurrentUserAsync();
var currentUser = await userManager.FindByIdAsync(currentUserModel.Id.ToString());
if (currentUser is null) return [];
var userRoles = await userManager.GetRolesAsync(currentUser);
return userRoles;
}
public async Task<string?> LoginAsync(string userName, string password)
{
var result =
await signInManager.PasswordSignInAsync(userName, password, isPersistent: false, lockoutOnFailure: false);
if (!result.Succeeded)
{
return null;
}
var user = await GetUserByUserNameAsync(userName);
if (user is null) throw new InvalidOperationException();
var token = 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,
alias: user.Alias,
firstname: user.Firstname,
lastname: user.Lastname,
portraitUrl: user.PortraitUrl);
return token;
}
}