using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; using Mapster; using Medallion.Threading; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using Newtonsoft.Json; using Volo.Abp.Caching; using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Services; using Volo.Abp.EventBus.Local; using Volo.Abp.Security.Claims; using Yi.Framework.Core.Helper; using Yi.Framework.Rbac.Domain.Entities; using Yi.Framework.Rbac.Domain.Repositories; using Yi.Framework.Rbac.Domain.Shared.Caches; using Yi.Framework.Rbac.Domain.Shared.Consts; using Yi.Framework.Rbac.Domain.Shared.Dtos; using Yi.Framework.Rbac.Domain.Shared.Etos; using Yi.Framework.Rbac.Domain.Shared.Model; using Yi.Framework.Rbac.Domain.Shared.Options; using Yi.Framework.SqlSugarCore.Abstractions; namespace Yi.Framework.Rbac.Domain.Managers { /// /// 用户领域服务 /// public class AccountManager : DomainService, IAccountManager { private readonly IUserRepository _repository; private readonly ILocalEventBus _localEventBus; private readonly JwtOptions _jwtOptions; private readonly RbacOptions _options; private UserManager _userManager; private ISqlSugarRepository _roleRepository; private RefreshJwtOptions _refreshJwtOptions; /// /// 缓存前缀 /// private string CacheKeyPrefix => LazyServiceProvider .LazyGetRequiredService>() .Value.KeyPrefix; public IDistributedLockProvider DistributedLock => LazyServiceProvider.LazyGetService(); public AccountManager(IUserRepository repository , IOptions jwtOptions , ILocalEventBus localEventBus , UserManager userManager , IOptions refreshJwtOptions , ISqlSugarRepository roleRepository , IOptions options) { _repository = repository; _jwtOptions = jwtOptions.Value; _localEventBus = localEventBus; _userManager = userManager; _roleRepository = roleRepository; _refreshJwtOptions = refreshJwtOptions.Value; _options = options.Value; } /// /// 根据用户id获取token /// /// /// /// /// public async Task GetTokenByUserIdAsync(Guid userId, Action? getUserInfo = null) { //获取用户信息 var userInfo = await _userManager.GetInfoAsync(userId); //判断用户状态 if (userInfo.User.State == false) { throw new UserFriendlyException(UserConst.State_Is_State); } if (userInfo.RoleCodes.Count == 0) { throw new UserFriendlyException(UserConst.No_Role); } if (!userInfo.PermissionCodes.Any()) { throw new UserFriendlyException(UserConst.No_Permission); } if (getUserInfo is not null) { getUserInfo(userInfo); } var accessToken = CreateToken(this.UserInfoToClaim(userInfo)); //将用户信息添加到缓存中,需要考虑的是更改了用户、角色、菜单等整个体系都需要将缓存进行刷新,看具体业务进行选择 return accessToken; } /// /// 创建令牌 /// /// /// private string CreateToken(List> kvs) { var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtOptions.SecurityKey)); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var claims = kvs.Select(x => new Claim(x.Key, x.Value.ToString())).ToList(); var token = new JwtSecurityToken( issuer: _jwtOptions.Issuer, audience: _jwtOptions.Audience, claims: claims, expires: DateTime.Now.AddSeconds(_jwtOptions.ExpiresSecondTime), notBefore: DateTime.Now, signingCredentials: creds); string returnToken = new JwtSecurityTokenHandler().WriteToken(token); return returnToken; } public string CreateRefreshToken(Guid userId) { var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_refreshJwtOptions.SecurityKey)); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); //添加用户id,及刷新token的标识 var claims = new List { new Claim(AbpClaimTypes.UserId, userId.ToString()), new Claim(TokenTypeConst.Refresh, "true") }; var token = new JwtSecurityToken( issuer: _refreshJwtOptions.Issuer, audience: _refreshJwtOptions.Audience, claims: claims, expires: DateTime.Now.AddSeconds(_refreshJwtOptions.ExpiresSecondTime), notBefore: DateTime.Now, signingCredentials: creds); string returnToken = new JwtSecurityTokenHandler().WriteToken(token); return returnToken; } /// /// 登录校验 /// /// /// /// /// public async Task LoginValidationAsync(string userName, string password, Action userAction = null) { var user = new UserAggregateRoot(); if (await ExistAsync(userName, o => user = o)) { if (userAction is not null) { userAction.Invoke(user); } if (user.EncryPassword.Password == MD5Helper.SHA2Encode(password, user.EncryPassword.Salt)) { return; } throw new UserFriendlyException(UserConst.Login_Error); } throw new UserFriendlyException(UserConst.Login_User_No_Exist); } /// /// 判断账户合法存在 /// /// /// /// public async Task ExistAsync(string userName, Action userAction = null) { var user = await _repository.GetFirstAsync(u => u.UserName == userName && u.State == true); if (userAction is not null) { userAction.Invoke(user); } //这里为了兼容解决数据库开启了大小写不敏感问题,还要将用户名进行二次校验 if (user != null && user.UserName == userName) { return true; } return false; } /// /// 令牌转换 /// /// /// public List> UserInfoToClaim(UserRoleMenuDto dto) { var claims = new List>(); AddToClaim(claims, AbpClaimTypes.UserId, dto.User.Id.ToString()); AddToClaim(claims, AbpClaimTypes.UserName, dto.User.UserName); if (dto.User.DeptId is not null) { AddToClaim(claims, TokenTypeConst.DeptId, dto.User.DeptId.ToString()); } if (dto.User.Email is not null) { AddToClaim(claims, AbpClaimTypes.Email, dto.User.Email); } if (dto.User.Phone is not null) { AddToClaim(claims, AbpClaimTypes.PhoneNumber, dto.User.Phone.ToString()); } if (dto.Roles.Count > 0) { AddToClaim(claims, TokenTypeConst.RoleInfo, JsonConvert.SerializeObject(dto.Roles.Select(x => new RoleTokenInfoModel { Id = x.Id, DataScope = x.DataScope }))); } if (UserConst.Admin.Equals(dto.User.UserName)) { AddToClaim(claims, TokenTypeConst.Permission, UserConst.AdminPermissionCode); AddToClaim(claims, TokenTypeConst.Roles, UserConst.AdminRolesCode); } else { dto.PermissionCodes?.ToList()?.ForEach(per => AddToClaim(claims, TokenTypeConst.Permission, per)); dto.RoleCodes?.ToList()?.ForEach(role => AddToClaim(claims, AbpClaimTypes.Role, role)); } return claims; } private void AddToClaim(List> claims, string key, string value) { claims.Add(new KeyValuePair(key, value)); } /// /// 更新密码 /// /// /// /// /// /// public async Task UpdatePasswordAsync(Guid userId, string newPassword, string oldPassword) { var user = await _repository.GetByIdAsync(userId); if (!user.JudgePassword(oldPassword)) { throw new UserFriendlyException("无效更新!原密码错误!"); } user.EncryPassword.Password = newPassword; user.BuildPassword(); await _repository.UpdateAsync(user); } /// /// 重置密码,也可以是找回密码 /// /// /// /// public async Task RestPasswordAsync(Guid userId, string password) { var user = await _repository.GetByIdAsync(userId); user.EncryPassword.Password = password; user.BuildPassword(); return await _repository.UpdateAsync(user); } /// /// 注册用户,创建用户之后设置默认角色 /// /// /// /// /// /// /// /// public async Task RegisterAsync(string userName, string password, long? phone, string? email, string? nick, string? icon) { if (userName is null) { throw new UserFriendlyException("注册时,用户名不能为空"); } //制作幂等 await using (var handle = await DistributedLock.TryAcquireLockAsync($"{CacheKeyPrefix}Register:Lock:{userName}", TimeSpan.FromSeconds(60))) { if (handle is null) { throw new UserFriendlyException($"{userName}用户正在注册中,请稍等。。。"); } var userUpName = userName.ToUpper(); if (await _userManager._repository._DbQueryable.Where(x => x.UserName.ToUpper() == userUpName) .AnyAsync()) { throw new UserFriendlyException($"{userName}用户已注册"); } var user = new UserAggregateRoot(userName, password, phone, email, nick, icon); var userId = await _userManager.CreateAsync(user); await _userManager.SetDefautRoleAsync(user.Id); return userId; } } } }