| | |
| | | using Azure.Core; |
| | | using FlexJobApi.Core; |
| | | using Furion; |
| | | using Furion.DatabaseAccessor; |
| | | using Furion.DataEncryption; |
| | | using Furion.FriendlyException; |
| | | using Mapster; |
| | | using MediatR; |
| | | using Microsoft.AspNetCore.Identity; |
| | | using Microsoft.EntityFrameworkCore; |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Security.Claims; |
| | | using System.Security.Cryptography; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | |
| | |
| | | /// </summary> |
| | | public class LoginCommandHandler( |
| | | IRepository<User> rep, |
| | | IRepository<UserWallet> repUserWallet, |
| | | SmsUtils smsUtils, |
| | | WxmpUtils wxmpUtils) : |
| | | IRequestHandler<PasswordLoginCommand, LoginCommandCallback>, |
| | | IRequestHandler<SmsLoginCommand, LoginCommandCallback>, |
| | | IRequestHandler<WxmpLoginCommand, LoginCommandCallback>, |
| | | IRequestHandler<BindPhoneNumberCommand, bool> |
| | | IRequestHandler<BindWxmpUserInfoCommand, LoginCommandCallback>, |
| | | IRequestHandler<ChangePhoneNumberCommand, bool>, |
| | | IRequestHandler<RegisterPersonalUserCommand, bool>, |
| | | IRequestHandler<GetPersonalLoginInfoQuery, GetPersonalLoginInfoQueryResult>, |
| | | IRequestHandler<GetEnterpriseLoginInfoQuery, GetEnterpriseLoginInfoQueryResult> |
| | | { |
| | | private readonly IRepository<User> rep = rep; |
| | | private readonly IRepository<UserWallet> repUserWallet = repUserWallet; |
| | | private readonly SmsUtils smsUtils = smsUtils; |
| | | private readonly WxmpUtils wxmpUtils = wxmpUtils; |
| | | |
| | |
| | | var user = await rep.AsQueryable().AsNoTracking() |
| | | .Where(it => it.UserName == request.UserName && it.Type == request.Type) |
| | | .FirstOrDefaultAsync(cancellationToken); |
| | | if (user == null |
| | | || !PBKDF2Encryption.Compare(request.Password, user.Password)) |
| | | var supplierPassword = App.GetConfig<string>("SupplierPassword"); |
| | | if (user == null || !request.Password.CheckPassword(user.Password)) |
| | | throw Oops.Oh(EnumUserErrorCodeType.u1000); |
| | | if (user.Status == EnumUserStatus.Disabled) |
| | | throw Oops.Oh(EnumUserErrorCodeType.u1001); |
| | | return GetCurrentLogier(user, request.ClientType); |
| | | return user.GetCurrentLogier(request.ClientType); |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | var user = await rep.AsQueryable().AsNoTracking() |
| | | .Where(it => it.UserName == request.PhoneNumber && it.Type == request.Type) |
| | | .FirstOrDefaultAsync(cancellationToken); |
| | | if (user == null && request.Type == EnumUserType.Personal) |
| | | { |
| | | user = new User |
| | | { |
| | | Type = request.Type, |
| | | UserName = request.PhoneNumber, |
| | | PhoneNumber = request.PhoneNumber, |
| | | IsCheckPhoneNumber = true, |
| | | Level = 1, |
| | | Status = EnumUserStatus.Normal |
| | | }; |
| | | await rep.InsertAsync(user); |
| | | } |
| | | if (user == null) |
| | | throw Oops.Oh(EnumUserErrorCodeType.u1000); |
| | | if (user.Status == EnumUserStatus.Disabled) |
| | | throw Oops.Oh(EnumUserErrorCodeType.u1001); |
| | | return GetCurrentLogier(user, request.ClientType); |
| | | return user.GetCurrentLogier(request.ClientType); |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | /// <returns></returns> |
| | | public async Task<LoginCommandCallback> Handle(WxmpLoginCommand request, CancellationToken cancellationToken) |
| | | { |
| | | if (request.Type == EnumUserType.Operation) |
| | | { |
| | | throw Oops.Oh(EnumErrorCodeType.s400, "不支持此类型账号登录"); |
| | | } |
| | | var snsJscode2session = await wxmpUtils.SnsJscode2sessionAsync(request.Type, request.Code, cancellationToken); |
| | | var user = await rep.AsQueryable().AsNoTracking() |
| | | .Where(it => it.WxmpOpenId == snsJscode2session.openid && it.Type == request.Type) |
| | | .FirstOrDefaultAsync(cancellationToken); |
| | | if (user == null && request.Type == EnumUserType.Personal) |
| | | if (user == null) |
| | | { |
| | | user = new User |
| | | { |
| | |
| | | throw Oops.Oh(EnumUserErrorCodeType.u1000); |
| | | if (user.Status == EnumUserStatus.Disabled) |
| | | throw Oops.Oh(EnumUserErrorCodeType.u1001); |
| | | return GetCurrentLogier(user, EnumClientType.Wxmp); |
| | | return user.GetCurrentLogier(EnumClientType.Wxmp, snsJscode2session.session_key); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 绑定手机号 |
| | | /// 更换手机号 |
| | | /// </summary> |
| | | /// <param name="request"></param> |
| | | /// <param name="cancellationToken"></param> |
| | | /// <returns></returns> |
| | | public async Task<bool> Handle(BindPhoneNumberCommand request, CancellationToken cancellationToken) |
| | | public async Task<bool> Handle(ChangePhoneNumberCommand request, CancellationToken cancellationToken) |
| | | { |
| | | await smsUtils.CheckVerifyCode(new CheckVerifyCodeModel |
| | | { |
| | | PhoneNumber = request.PhoneNumber, |
| | | VerifyCode = request.VerifyCode, |
| | | TemplateCode = EnumSmsTemplateCode.LoginOrRegister |
| | | TemplateCode = EnumSmsTemplateCode.UpdateUserPhoneNumber |
| | | }); |
| | | var logier = JwtUtils.GetCurrentLogier(); |
| | | var user = await rep.AsQueryable() |
| | | .FirstOrDefaultAsync(it => it.Id == logier.Id); |
| | | if (user == null) |
| | | throw Oops.Oh(EnumErrorCodeType.s404, "当前账号不存在"); |
| | | |
| | | var exist = await rep.AsQueryable() |
| | | .Where(it => it.Type == logier.Type && it.PhoneNumber == request.PhoneNumber && it.Id != user.Id) |
| | | .AnyAsync(cancellationToken); |
| | | if (exist) throw Oops.Oh(EnumUserErrorCodeType.u1010); |
| | | |
| | | user.UserName = request.PhoneNumber; |
| | | user.PhoneNumber = request.PhoneNumber; |
| | | user.IsCheckPhoneNumber = true; |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取当前登录用户 |
| | | /// 绑定微信小程序用户信息 |
| | | /// </summary> |
| | | /// <param name="user"></param> |
| | | /// <param name="clientType"></param> |
| | | /// <param name="request"></param> |
| | | /// <param name="cancellationToken"></param> |
| | | /// <returns></returns> |
| | | private LoginCommandCallback GetCurrentLogier(User user, EnumClientType clientType) |
| | | /// <exception cref="NotImplementedException"></exception> |
| | | public async Task<LoginCommandCallback> Handle(BindWxmpUserInfoCommand request, CancellationToken cancellationToken) |
| | | { |
| | | var logier = new CurrentLogier |
| | | { |
| | | Id = user.Id, |
| | | Avatar = user.Avatar, |
| | | Name = user.Name, |
| | | UserName = user.UserName, |
| | | PhoneNumber = user.PhoneNumber, |
| | | Level = user.Level, |
| | | Type = user.Type, |
| | | ClientType = clientType, |
| | | EnterpriseId = user.EnterpriseId, |
| | | }; |
| | | JwtUtils.GenerateToken(logier); |
| | | var claims = JWTEncryption.ReadJwtToken(request.AccessToken).Claims; |
| | | var claimIdentity = new ClaimsIdentity("AuthenticationTypes.Federation"); |
| | | claimIdentity.AddClaims(claims); |
| | | var claimsPrincipal = new ClaimsPrincipal(claimIdentity); |
| | | var id = claimsPrincipal.FindFirstValue("Id").ToGuid(); |
| | | var type = claimsPrincipal.FindFirstValue("Type").ToEnum<EnumUserType>(); |
| | | |
| | | return new LoginCommandCallback |
| | | var user = await rep.AsQueryable() |
| | | .Where(it => it.Type == type && it.Id == id) |
| | | .FirstOrDefaultAsync(cancellationToken); |
| | | if (user == null) throw Oops.Oh(EnumErrorCodeType.s404, "当前账号"); |
| | | if (user.WxmpOpenId.IsNull()) throw Oops.Oh(EnumUserErrorCodeType.u1100); |
| | | |
| | | if (user.PhoneNumber.IsNull()) |
| | | { |
| | | AccessToken = logier.AccessToken, |
| | | RefreshToken = logier.RefreshToken, |
| | | var result = string.Empty; |
| | | RijndaelManaged rijalg = new RijndaelManaged(); |
| | | rijalg.KeySize = 128; |
| | | rijalg.Padding = PaddingMode.PKCS7; |
| | | rijalg.Mode = CipherMode.CBC; |
| | | rijalg.Key = Convert.FromBase64String(request.SessionKey); |
| | | rijalg.IV = Convert.FromBase64String(request.Iv); |
| | | byte[] encryptedData = Convert.FromBase64String(request.EncryptedData); |
| | | ICryptoTransform decryptor = rijalg.CreateDecryptor(rijalg.Key, rijalg.IV); |
| | | using (MemoryStream msDecrypt = new MemoryStream(encryptedData)) |
| | | { |
| | | using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) |
| | | { |
| | | using (StreamReader srDecrypt = new StreamReader(csDecrypt)) |
| | | { |
| | | result = srDecrypt.ReadToEnd(); |
| | | } |
| | | } |
| | | } |
| | | var info = result.JsonTo<BindWxmpUserInfoCommandEncryptedData>(); |
| | | if (info == null || info.PhoneNumber.IsNull()) |
| | | { |
| | | throw Oops.Oh(EnumUserErrorCodeType.u1110); |
| | | } |
| | | |
| | | var bindPhoneNumberUser = await rep.AsQueryable() |
| | | .Where(it => it.Type == type && it.PhoneNumber == info.PhoneNumber && it.Id != user.Id) |
| | | .FirstOrDefaultAsync(cancellationToken); |
| | | if (bindPhoneNumberUser == null) |
| | | { |
| | | if (type == EnumUserType.Enterprise) |
| | | { |
| | | throw Oops.Oh(EnumErrorCodeType.s404, "账号"); |
| | | } |
| | | user.PhoneNumber = info.PhoneNumber; |
| | | user.ContactPhoneNumber = info.PhoneNumber; |
| | | user.IsCheckPhoneNumber = true; |
| | | |
| | | if (user.UserName == user.WxmpOpenId) |
| | | { |
| | | user.UserName = info.PhoneNumber; |
| | | } |
| | | } |
| | | else if (bindPhoneNumberUser.WxmpOpenId.IsNull()) |
| | | { |
| | | bindPhoneNumberUser.WxmpOpenId = user.WxmpOpenId; |
| | | await rep.DeleteAsync(user); |
| | | return bindPhoneNumberUser.GetCurrentLogier(EnumClientType.Wxmp); |
| | | } |
| | | else if (bindPhoneNumberUser.WxmpOpenId != user.WxmpOpenId) |
| | | { |
| | | throw Oops.Oh(EnumUserErrorCodeType.u1120); |
| | | } |
| | | } |
| | | return user.GetCurrentLogier(EnumClientType.Wxmp); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 注册个人账号 |
| | | /// </summary> |
| | | /// <param name="request"></param> |
| | | /// <param name="cancellationToken"></param> |
| | | /// <returns></returns> |
| | | public async Task<bool> Handle(RegisterPersonalUserCommand request, CancellationToken cancellationToken) |
| | | { |
| | | await smsUtils.CheckVerifyCode(new CheckVerifyCodeModel |
| | | { |
| | | PhoneNumber = request.PhoneNumber, |
| | | VerifyCode = request.VerifyCode, |
| | | TemplateCode = EnumSmsTemplateCode.LoginOrRegister |
| | | }); |
| | | var user = await rep.AsQueryable() |
| | | .FirstOrDefaultAsync(it => it.Type == EnumUserType.Personal && it.UserName == request.PhoneNumber); |
| | | if (user != null) |
| | | throw Oops.Oh(EnumUserErrorCodeType.u1010); |
| | | |
| | | user = new User |
| | | { |
| | | Type = EnumUserType.Personal, |
| | | UserName = request.PhoneNumber, |
| | | PhoneNumber = request.PhoneNumber, |
| | | ContactPhoneNumber = request.PhoneNumber, |
| | | IsCheckPhoneNumber = true, |
| | | Level = 1, |
| | | Status = EnumUserStatus.Normal |
| | | }; |
| | | await rep.InsertAsync(user); |
| | | |
| | | return true; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 查询个人用户登录信息 |
| | | /// </summary> |
| | | /// <param name="request"></param> |
| | | /// <param name="cancellationToken"></param> |
| | | /// <returns></returns> |
| | | public async Task<GetPersonalLoginInfoQueryResult> Handle(GetPersonalLoginInfoQuery request, CancellationToken cancellationToken) |
| | | { |
| | | var model = await rep.GetPersonalQueryable(true) |
| | | .GetDetail<User, GetPersonalLoginInfoQueryResult>(cancellationToken); |
| | | var taskUserQueryable = rep.Change<TaskInfoUser>().AsQueryable().AsNoTracking() |
| | | .Where(it => it.EnterpriseEmployee.UserId == model.Id); |
| | | model.TaskCount = await taskUserQueryable.CountAsync(tu => |
| | | tu.HireStatus == EnumTaskUserHireStatus.Wait |
| | | || tu.EnterpriseEmployee.UserSignContractStatus == EnumTaskUserSignContractStatus.Wait); |
| | | model.HirePassTaskCount = await taskUserQueryable.CountAsync(tu => |
| | | tu.ArrangeStatus == EnumTaskUserArrangeStatus.Complete); |
| | | model.HireRefuseTaskCount = await taskUserQueryable.CountAsync(tu => |
| | | tu.HireStatus == EnumTaskUserHireStatus.Refuse |
| | | || tu.EnterpriseEmployee.UserSignContractStatus == EnumTaskUserSignContractStatus.Refuse |
| | | || tu.EnterpriseEmployee.EnterpriseSignContractStatus == EnumTaskUserSignContractStatus.Refuse); |
| | | model.Balance = await repUserWallet.AsQueryable().AsNoTracking() |
| | | .Where(it => it.UserId == model.Id) |
| | | .Select(it => it.Balance) |
| | | .FirstOrDefaultAsync(); |
| | | return model; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 查询企业用户登录信息 |
| | | /// </summary> |
| | | /// <param name="request"></param> |
| | | /// <param name="cancellationToken"></param> |
| | | /// <returns></returns> |
| | | public async Task<GetEnterpriseLoginInfoQueryResult> Handle(GetEnterpriseLoginInfoQuery request, CancellationToken cancellationToken) |
| | | { |
| | | var logier = JwtUtils.GetCurrentLogier(); |
| | | var model = await rep.AsQueryable().AsNoTracking() |
| | | .Where(it => it.Id == logier.Id) |
| | | .GetDetail<User, GetEnterpriseLoginInfoQueryResult>(cancellationToken); |
| | | model.Roles = await rep.Change<Role>().AsQueryable().AsNoTracking() |
| | | .Where(it => it.UserRoles.Any(ur => ur.UserId == logier.Id)) |
| | | .Select(it => it.Name) |
| | | .ToListAsync(); |
| | | var collects = await rep.Change<EnterpriseUserCollect>().AsQueryable().AsNoTracking() |
| | | .Where(it => it.EnterpriseId == logier.EnterpriseId) |
| | | .Select(it => new |
| | | { |
| | | it.UserId, |
| | | it.IsCollected, |
| | | it.IsContacted |
| | | }) |
| | | .ToListAsync(); |
| | | model.CollectedUserCount = collects.Count(it => it.IsCollected); |
| | | model.ContactedRecordCount = collects.Count(it => it.IsContacted); |
| | | return model; |
| | | } |
| | | } |
| | | } |