using AutoMapper; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Json; using System.Linq; using System.Text; using System.Threading.Tasks; using WMS.Web.Core.Dto.Login; using WMS.Web.Core.Dto.Login.Temp; using WMS.Web.Core.Dto.Login.Temp.v3; using WMS.Web.Core.Dto.SingleData; using WMS.Web.Core.Help; using WMS.Web.Core.Internal.Results; using WMS.Web.Core.Internal.Security; using WMS.Web.Domain.IService.Public; using WMS.Web.Domain.Options; using WMS.Web.Domain.Values.Single; namespace WMS.Web.Domain.Services.Public { public class LoginService : ILoginService { private IMapper _mapper; private SoaOptions _soaOptions; private ILogger _logger; private HttpClientHelp _httpClientHelp; private readonly ISingleDataService _singleDataService; private readonly RedisClientService _redisClientService; public LoginService( IMapper mapper, IOptions soaOptions, ILogger logger, HttpClientHelp httpClientHelp, ISingleDataService singleDataService, RedisClientService redisClientService) { this._redisClientService = redisClientService; this._singleDataService = singleDataService; this._soaOptions = soaOptions?.Value; this._mapper = mapper; this._logger = logger; this._httpClientHelp = httpClientHelp; } /// /// 创建token /// /// /// /// /// public async Task CreateToken(UserInfoDto data, LoginTempDto tempDto, string NewToken) { return await Task.Run(() => { DateTime expires_time = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1)).AddSeconds(tempDto.expires_in); AccessTokenDto accessToken = new AccessTokenDto() { Token = NewToken, PhpToken = tempDto.access_token, RefreshToken = tempDto.refresh_token, Expired = expires_time }; return accessToken; }); } /// /// 创建token /// /// /// /// /// private async Task CreateToken(UserInfoDto data, LoginTempV2Dto tempDto, string NewToken) { return await Task.Run(() => { DateTime expires_time = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1)).AddSeconds(tempDto.access_expired_at); AccessTokenDto accessToken = new AccessTokenDto() { Token = NewToken, PhpToken = tempDto.access_token, RefreshToken = tempDto.refresh_token, Expired = expires_time }; return accessToken; }); } /// /// 获取单点登录信息 /// /// /// public async Task> GetUserInfoByCode(string code) { var reqData = new LoginAuthorizeCodeRequest(); reqData.ClientId = _soaOptions.AppId; reqData.ClientSecret = _soaOptions.AppSecret; reqData.GrantType = "authorization_code"; reqData.Code = code; reqData.Scope = "credentials"; //这个是登录的时候给前端验证的token,以及传给php单点那边的一个session值,用于单点退出时,通知ops退出 string NewToken = Guid.NewGuid().ToString("N"); try { string result = _httpClientHelp.PostHttp(_soaOptions.Url_V3 + "/uc/authorize", reqData); var jObject = JsonObject.Parse(result); LoginInDto r = new LoginInDto(); r.UserInfo = new UserInfoDto(); r.TokenInfo = new AccessTokenDto(); var login_result = jObject["code"] == 0 ? "成功" : "失败"; if (jObject["code"] == 0) { string datajson = jObject["data"].ToString(); var _loginDto = JsonConvert.DeserializeObject(datajson); #region 解码 string enptStr = _loginDto.encrypted_data; List enptlist = enptStr.Trim().Split(',').ToList(); string str = RSA.DecryptSection(_soaOptions.PrivateKey, enptlist); var entity = JsonConvert.DeserializeObject(str); #endregion //映射登录信息 var userInfo_v3 = _mapper.Map(entity); _logger.LogInformation($"登录信息:用户ID->{entity.id}"); //HTTP请求获取登录信息:人员,客户,供应商,公司 var loginRequest = new LoginSingleRequest() { UserId = entity.id, }; var loginResponse_result = await _singleDataService.GetSingleDataNoCache, LoginSingleRequest, SingleLoginAction> (loginRequest, SingleLoginAction.Staff, type: SingleControllerType.Login); //绑定返回对象的登录信息 var staffName = "Null"; var token = await CreateToken(r.UserInfo, _loginDto, NewToken); r.TokenInfo = token; if (loginResponse_result.Success && loginResponse_result.Data != null) { var loginResponse = loginResponse_result.Data; if (loginResponse != null) { r.UserInfo.StaffId = loginResponse.Id; staffName = loginResponse.Name; } } r.UserInfo.CompanyId = userInfo_v3.Company.Id; r.UserInfo.CompanyName = userInfo_v3.Company.Name; r.UserInfo.UcId = userInfo_v3.Id; r.UserInfo.SeesionId = "";//app和程序类型登录授权没有这个字段 r.UserInfo.Nickname = userInfo_v3.Nickname; r.UserInfo.Mobile = userInfo_v3.Mobile; r.UserInfo.Identity = userInfo_v3.Identity; r.UserInfo.OrgId = entity.orgs.FirstOrDefault()?.org_id; r.UserInfo.CustomerId = null; r.UserInfo.SupplierId = null; r.SignedIn = true; //登录后缓存登录的用户信息和token信息 var loginInfo = new LoginInDto(); loginInfo.UserInfo = r.UserInfo; loginInfo.TokenInfo = token; loginInfo.TokenInfo.ClientName = "PC"; var ops_login_time = token.Expired.AddDays(1) - DateTime.Now;//用于正式 //var ops_login_time = token.Expired - DateTime.Now;//用于正式 _redisClientService.SetStringKey($"wms_login_{token.Token}", loginInfo, ops_login_time); _logger.LogInformation($"登录信息:用户人员信息->{staffName}({r.UserInfo.StaffId}),公司名称->{r.UserInfo.CompanyName}"+",过期时间:"+token.Expired.ToString("yyyy-MM-dd HH:mm:ss")); //登录成功移出对应的用户token黑名单:应为新的token产生,移除登录的信息 string blacktoken = _redisClientService.GetStringKey($"wms_black_token_{r.UserInfo.UcId}"); if (!string.IsNullOrEmpty(blacktoken)) { this.RemoveLoginInfo(blacktoken); _redisClientService.RemoveStringKey($"wms_black_token_{r.UserInfo.UcId}"); } if (r == null || r.UserInfo == null || r.TokenInfo == null) return Result.ReFailure("授权失败,请重新登录", 401); return Result.ReSuccess(r); } else { var errno_text = "登录失败:" + jObject["message"]; _logger.LogInformation("登陆失败:" + errno_text); return Result.ReFailure(errno_text, 401); } } catch (Exception ex) { _logger.LogInformation("登录错误信息:" + ex.Message); return Result.ReFailure("授权失败,请重新登录", 401); } } /// /// 获取单点用户信息 /// /// /// /// public async Task> GetUserInfo(string username, string password) { var reqData = new LoginAuthorizeRequest(); reqData.ClientId = _soaOptions.AppId; reqData.ClientSecret = _soaOptions.AppSecret; reqData.GrantType = "password"; reqData.UserName = username; reqData.Scope = "credentials"; _logger.LogInformation($"username:"+ username+";password:"+password); var md5 = System.Security.Cryptography.MD5.Create(); var md5Pwd= BitConverter.ToString(md5.ComputeHash(Encoding.Default.GetBytes(password))); md5Pwd = md5Pwd.Replace("-", string.Empty); reqData.Password = md5Pwd.ToLower(); //这个是登录的时候给前端验证的token,以及传给php单点那边的一个session值,用于单点退出时,通知ops退出 string NewToken = Guid.NewGuid().ToString("N"); try { string result = _httpClientHelp.PostHttp(_soaOptions.Url_V3 + "/uc/authorize", reqData); var jObject = JsonObject.Parse(result); LoginInDto r = new LoginInDto(); r.UserInfo = new UserInfoDto(); r.TokenInfo = new AccessTokenDto(); var login_result = jObject["code"] == 0 ? "成功" : "失败"; if (jObject["code"] == 0) { string datajson = jObject["data"].ToString(); var _loginDto = JsonConvert.DeserializeObject(datajson); #region 解码 string enptStr = _loginDto.encrypted_data; List enptlist = enptStr.Trim().Split(',').ToList(); string str = RSA.DecryptSection(_soaOptions.PrivateKey, enptlist); var entity = JsonConvert.DeserializeObject(str); #endregion //映射登录信息 var userInfo_v3 = _mapper.Map(entity); _logger.LogInformation($"登录信息:用户ID->{entity.id}"); //HTTP请求获取登录信息:人员,客户,供应商,公司 var loginRequest = new LoginSingleRequest() { UserId = entity.id, }; var loginResponse_result = await _singleDataService.GetSingleDataNoCache, LoginSingleRequest, SingleLoginAction> (loginRequest, SingleLoginAction.Staff, type: SingleControllerType.Login); //绑定返回对象的登录信息 var staffName = "Null"; var token = await CreateToken(r.UserInfo, _loginDto, NewToken); r.TokenInfo = token; if (loginResponse_result.Success && loginResponse_result.Data != null) { var loginResponse = loginResponse_result.Data; if (loginResponse != null) { r.UserInfo.StaffId = loginResponse.Id; staffName = loginResponse.Name; } } r.UserInfo.CompanyId = userInfo_v3.Company.Id; r.UserInfo.CompanyName = userInfo_v3.Company.Name; r.UserInfo.UcId = userInfo_v3.Id; r.UserInfo.SeesionId ="";//app和程序类型登录授权没有这个字段 r.UserInfo.Nickname = userInfo_v3.Nickname; r.UserInfo.Mobile = userInfo_v3.Mobile; r.UserInfo.Identity = userInfo_v3.Identity; r.UserInfo.OrgId = entity.orgs.FirstOrDefault()?.org_id; r.UserInfo.CustomerId = null; r.UserInfo.SupplierId = null; r.SignedIn = true; _logger.LogInformation($"登录信息:用户人员信息->{staffName}({r.UserInfo.StaffId}),公司名称->{r.UserInfo.CompanyName}"); //登录后缓存登录的用户信息和token信息 var loginInfo = new LoginInDto(); loginInfo.UserInfo = r.UserInfo; loginInfo.TokenInfo = token; loginInfo.TokenInfo.ClientName = "PDA"; var ops_login_time = token.Expired.AddDays(1) - DateTime.Now;//用于正式 //var ops_login_time = token.Expired - DateTime.Now;//用于正式 _redisClientService.SetStringKey($"wms_login_{token.Token}", loginInfo, ops_login_time); //登录成功移出对应的用户token黑名单:应为新的token产生,移除登录的信息 string blacktoken = _redisClientService.GetStringKey($"wms_black_token_{r.UserInfo.UcId}"); if (!string.IsNullOrEmpty(blacktoken)) { this.RemoveLoginInfo(blacktoken); _redisClientService.RemoveStringKey($"wms_black_token_{r.UserInfo.UcId}"); } if (r == null || r.UserInfo == null || r.TokenInfo == null) return Result.ReFailure("授权失败,请重新登录", 401); return Result.ReSuccess(r); } else { var errno_text = "登录失败:" + jObject["message"]; _logger.LogInformation("登陆失败:" + errno_text); return Result.ReFailure(errno_text, 4001); //r.SignedIn = false; //string datajson_sessid = jObject["data"]["uc_sessid"]; ////调用单点的退出接口 //result = _httpClientHelp.GetHttp(_soaOptions.Url + "/uc/authorize/signin_out", true, cookieValue: datajson_sessid); //jObject = JsonObject.Parse(result); //if (jObject["errno"] == 0) //{ // return Result.ReFailure("拒绝用户证书试图访问此web站点,请与站点管理员联系以建立用户证书权限", 403); //} //else //{ // return Result.ReFailure(jObject["errmsg"], jObject["errno"]); //} } } catch (Exception ex) { _logger.LogInformation("登录错误信息:" + ex.Message); return Result.ReFailure("授权失败,请重新登录", 401); } } /// /// 登录退出 /// /// /// public async Task LoginOut(LoginOutDto dto) { //2.请求PHP单点登出接口 var reqData = new LoginOutAuthorizeRequest(); reqData.AccessToken = dto.AccessToken; reqData.RefreshToken = dto.RefreshToken; string result = _httpClientHelp.GetHttpOut(_soaOptions.Url_V3 + "/uc/logout", reqData); _logger.LogInformation($"退出参数:{JsonConvert.SerializeObject(dto)}->退出登录单点返回:" + result); var jObject = JsonObject.Parse(result); if (jObject["code"] == 0) { //设置本地token的缓存:为黑名单的token做存储 await CacheOutToken(dto); return Result.ReSuccess(); } else { return Result.ReFailure(BaseResultCodes.UnAuthorized); } } /// /// 刷新token /// /// /// /// public async Task> RefreshTokenNew(string oldToken, string RefreshToken) { //1.根据旧token 找到登录对象 var loginInfo = _redisClientService.GetStringKey($"wms_login_{oldToken}"); var reqData = new LoginAuthorizeRefreshTokenRequest(); reqData.ClientId = _soaOptions.AppId; reqData.ClientSecret = _soaOptions.AppSecret; reqData.GrantType = "refresh_token"; reqData.RefreshToken = RefreshToken; reqData.Scope = "credentials"; var clientName = loginInfo?.TokenInfo?.ClientName; var oldExpired = loginInfo?.TokenInfo?.Expired.ToString("yyyy-MM-dd HH:mm:ss"); try { string result = _httpClientHelp.PostHttp(_soaOptions.Url_V3 + "/uc/authorize", reqData); var jObject = JsonObject.Parse(result); LoginInDto r = new LoginInDto(); r.UserInfo = new UserInfoDto(); r.TokenInfo = new AccessTokenDto(); if (jObject["code"] == 0) { string datajson = jObject["data"].ToString(); var _loginDto = JsonConvert.DeserializeObject(datajson); r.UserInfo = loginInfo.UserInfo; r.SignedIn = true; //string NewToken = Guid.NewGuid().ToString("N"); var token = await CreateToken(loginInfo.UserInfo, _loginDto, oldToken); r.TokenInfo = token; loginInfo.TokenInfo = token; loginInfo.TokenInfo.ClientName = clientName; //_logger.LogInformation("RefreshToken:我在刷新登录:刷新后的过期时间-1>" + token.Expired.ToString()); var ops_login_time = token.Expired.AddDays(1) - DateTime.Now;//用于正式 //var ops_login_time = token.Expired - DateTime.Now;//用于正式 _redisClientService.SetStringKey($"wms_login_{token.Token}", loginInfo, ops_login_time); _logger.LogInformation($"刷新Token->用户信息:{JsonConvert.SerializeObject(loginInfo)}->老时间->" + $"{oldExpired}"+",新时间->"+ $"wms_login_{token.Token}->过期时间:{token.Expired.ToString("yyyy-MM-dd HH:mm:ss")}"); //移除老的redis缓存 //_redisClientService.RemoveStringKey($"wms_login_{oldToken}"); //_logger.LogInformation("RefreshToken:我在刷新登录:刷新后的过期时间-小时->" + ops_login_time.Hours); return Result.ReSuccess(r); } else { //失败了1:就把登录的token清除 2: ucid添加到黑名单 var time = new TimeSpan(r.TokenInfo.Expired.Day, r.TokenInfo.Expired.Hour, r.TokenInfo.Expired.Minute, r.TokenInfo.Expired.Second, r.TokenInfo.Expired.Millisecond); _redisClientService.SetStringKey($"wms_black_token_{r.UserInfo.UcId}", r.TokenInfo.Token, time); this.RemoveLoginInfo(r.TokenInfo.Token); r.SignedIn = false; return Result.ReFailure(jObject["message"], jObject["code"]); } } catch (Exception ex) { _logger.LogInformation("RefreshTokenNew:" + _soaOptions.Url_V3 + "/uc/authorize" + ":Data:" + JsonConvert.SerializeObject(reqData)); _logger.LogInformation("RefreshTokenNew:Error" + ex.Message); return Result.ReFailure(ex.Message, 50001); } } /// /// 单点退出通知token失效 /// /// 这个是单点传过来的SeesionId /// public async Task LoginOutSingleAsync(string SeesionId) { var logininfo = _redisClientService.GetStringKey($"wms_login_{SeesionId}"); await Task.Run(() => { if (logininfo != null) { var cache_token = _redisClientService.GetStringKey($"wms_black_token_{logininfo.UserInfo.UcId}"); if (string.IsNullOrEmpty(cache_token)) { DateTime expires_time = logininfo.TokenInfo.Expired; var time = new TimeSpan(expires_time.Day, expires_time.Hour, expires_time.Minute, expires_time.Second, expires_time.Millisecond); _redisClientService.SetStringKey($"wms_black_token_{logininfo.UserInfo.UcId}", logininfo.TokenInfo.Token, time); this.RemoveLoginInfo(logininfo.TokenInfo.Token); } } }); } /// /// 缓存退出的token /// /// /// private async Task CacheOutToken(LoginOutDto dto) { await Task.Run(() => { if (!string.IsNullOrEmpty(dto.AccessToken)) { var time = new TimeSpan(dto.ExpiresIn.Day, dto.ExpiresIn.Hour, dto.ExpiresIn.Minute, dto.ExpiresIn.Second, dto.ExpiresIn.Millisecond); _redisClientService.SetStringKey($"wms_black_token_{dto.UcId}", dto.AccessToken, time); this.RemoveLoginInfo(dto.Token); } }); } /// /// 获取登录后的信息 /// /// /// public LoginInDto GetLoginInfo(string authorization) { string token = string.Empty; if (authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) { token = authorization.Substring("Bearer ".Length).Trim(); } var logininfo = _redisClientService.GetStringKey($"wms_login_{token}"); return logininfo; } /// /// 移除登录后的用户信息 /// /// private void RemoveLoginInfo(string token) { if (!string.IsNullOrEmpty(token)) { var info = _redisClientService.GetStringKey($"wms_login_{token}"); if (info != null) { _redisClientService.RemoveStringKey($"wms_login_{token}"); } } } /// /// 获取菜单数据 /// /// public async Task> GetMenuList(int userId) { int module = _soaOptions.ModuleID; var result = await _singleDataService.GetSingleDataNoCache, MenuRequest, SingleLoginAction> (new MenuRequest(userId, module), SingleLoginAction.Menus, type: SingleControllerType.Login); if (result.Success) return result.Data.ToList(); return null; } } }