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#
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();
|
|
}
|
|
} |