You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

173 lines
5.8 KiB
C#

using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Mapster;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using NPin.Framework.Upms.Domain.Entities;
using NPin.Framework.Upms.Domain.Repositories;
using NPin.Framework.Upms.Domain.Shared.Consts;
using NPin.Framework.Upms.Domain.Shared.Dtos;
using NPin.Framework.Upms.Domain.Shared.Etos;
using NPin.Framework.Upms.Domain.Shared.Options;
using Volo.Abp.Domain.Services;
using Volo.Abp.EventBus.Local;
using Volo.Abp.Security.Claims;
namespace NPin.Framework.Upms.Domain.Managers;
public interface IAccountManager
{
/// <summary>
/// 创建 RefreshToken
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
string CreateRefreshToken(Guid userId);
/// <summary>
/// 获取 AccessToken
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
Task<string> CreateAccessTokenAsync(Guid userId);
/// <summary>
/// 重置密码
/// </summary>
/// <param name="userId"></param>
/// <param name="password"></param>
/// <returns></returns>
Task<bool> RestPasswordAsync(Guid userId, string password);
/// <summary>
/// 修改密码
/// </summary>
/// <param name="userId"></param>
/// <param name="newPassword"></param>
/// <param name="oldPassword"></param>
/// <returns></returns>
Task UpdatePasswordAsync(Guid userId, string newPassword, string oldPassword);
}
public class AccountManager : DomainService, IAccountManager
{
private readonly IUserRepository _repository;
private readonly ILocalEventBus _localEventBus;
private readonly JwtOptions _jwtOptions;
private readonly RefreshJwtOptions _refreshJwtOptions;
private readonly UserManager _userManager;
private IHttpContextAccessor _httpContextAccessor;
public AccountManager(
IUserRepository repository,
ILocalEventBus localEventBus,
IOptions<JwtOptions> jwtOptions,
IOptions<RefreshJwtOptions> refreshJwtOptions,
UserManager userManager,
IHttpContextAccessor httpContextAccessor)
{
_repository = repository;
_localEventBus = localEventBus;
_jwtOptions = jwtOptions.Value;
_refreshJwtOptions = refreshJwtOptions.Value;
_userManager = userManager;
_httpContextAccessor = httpContextAccessor;
}
/// <summary>
/// 根据用户Id获取AccessToken
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
public async Task<string> CreateAccessTokenAsync(Guid userId)
{
var userInfo = await _userManager.GetInfoByCacheAsync(userId);
if (!userInfo.User.IsEnabled)
{
throw new UserFriendlyException("该用户已被禁用,请联系管理员进行恢复");
}
// http请求
if (_httpContextAccessor.HttpContext is not null)
{
// TODO eto 与 entity 保证
var loginLogEntity = LoginLogAggregateRoot.GetInfoByHttpContext(_httpContextAccessor.HttpContext);
var loginEto = loginLogEntity.Adapt<LoginEventArgs>();
loginEto.Username = userInfo.User.Username;
loginEto.UserId = userInfo.User.Id;
// 异步
_ = _localEventBus.PublishAsync(loginEto);
}
return CreateAccessToken(UserInfoToClaims(userInfo));
}
private string CreateAccessToken(List<KeyValuePair<string, string>> kvs)
{
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtOptions.SecurityKey));
// RSA2
var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var claims = kvs.Select(x => new Claim(x.Key, x.Value)).ToList();
var token = new JwtSecurityToken(
issuer: _jwtOptions.Issuer,
audience: _jwtOptions.Audience,
claims: claims,
expires: DateTime.Now.AddMinutes(_jwtOptions.ExpiresMinuteTime),
notBefore: DateTime.Now,
signingCredentials: credentials);
return new JwtSecurityTokenHandler().WriteToken(token);
}
public string CreateRefreshToken(Guid userId)
{
throw new NotImplementedException();
}
private List<KeyValuePair<string, string>> UserInfoToClaims(UserFullDto dto)
{
var claims = new List<KeyValuePair<string, string>>();
AddToClaim(claims, AbpClaimTypes.UserId, dto.User.Id.ToString());
AddToClaim(claims, AbpClaimTypes.UserName, dto.User.Username);
// TODO 各种 Claim
// 超级管理员
if (UserConst.Admin.Equals(dto.User.Username))
{
AddToClaim(claims, TokenTypeConst.Permission, UserConst.AdminPermissionCode);
AddToClaim(claims, TokenTypeConst.Roles, UserConst.AdminRoleCode);
}
else
{
}
return claims;
}
private void AddToClaim(List<KeyValuePair<string, string>> claims, string key, string value)
{
claims.Add(new KeyValuePair<string, string>(key, value));
}
/// <summary>
/// 重置密码(仅执行最终重置,无前序判断)
/// </summary>
/// <param name="userId"></param>
/// <param name="password"></param>
/// <returns></returns>
public async Task<bool> RestPasswordAsync(Guid userId, string password)
{
var user = await _repository.GetByIdAsync(userId);
user.EncryptPassword.Password = password;
user.BuildPassword();
return await _repository.UpdateAsync(user);
}
public Task UpdatePasswordAsync(Guid userId, string newPassword, string oldPassword)
{
throw new NotImplementedException();
}
}