Files
WMS-Api/src/WMS.Web.Domain/Services/Public/LoginService.cs
2023-11-11 17:40:21 +08:00

537 lines
25 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<LoginService> _logger;
private HttpClientHelp _httpClientHelp;
private readonly ISingleDataService _singleDataService;
private readonly RedisClientService _redisClientService;
public LoginService(
IMapper mapper,
IOptions<SoaOptions> soaOptions,
ILogger<LoginService> 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;
}
/// <summary>
/// 创建token
/// </summary>
/// <param name="data"></param>
/// <param name="tempDto"></param>
/// <param name="NewToken"></param>
/// <returns></returns>
private async Task<AccessTokenDto> 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;
});
}
/// <summary>
/// 创建token
/// </summary>
/// <param name="data"></param>
/// <param name="tempDto"></param>
/// <param name="NewToken"></param>
/// <returns></returns>
private async Task<AccessTokenDto> 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;
});
}
/// <summary>
/// 得到单点用户信息
/// </summary>
/// <param name="code"></param>
/// <returns></returns>
public async Task<Result<LoginInDto>> GetUserInfoAsync(string code)
{
JsonObject reqData = new JsonObject();
reqData.Add("app_id", _soaOptions.AppId);
reqData.Add("app_secret", _soaOptions.AppSecret);
reqData.Add("code", code);
//这个是登录的时候给前端验证的token,以及传给php单点那边的一个session值用于单点退出时通知ops退出
string NewToken = Guid.NewGuid().ToString("N");
try
{
string result = _httpClientHelp.PostHttp(_soaOptions.Url + "/uc/authorize/access_token", reqData, true, NewToken);
var jObject = JsonObject.Parse(result);
LoginInDto r = new LoginInDto();
r.UserInfo = new UserInfoDto();
r.TokenInfo = new AccessTokenDto();
var login_result = jObject["errno"] == 0 ? "成功" : "失败";
_logger.LogInformation($"登录信息:单点->{login_result}");
if (jObject["errno"] == 0)
{
string datajson = jObject["data"].ToString();
var _loginDto = JsonConvert.DeserializeObject<LoginTempDto>(datajson);
#region
string enptStr = _loginDto.encryptedData;
List<string> enptlist = enptStr.Trim().Split(',').ToList();
string str = RSA.DecryptSection(_soaOptions.PrivateKey, enptlist);
var entity = JsonConvert.DeserializeObject<LoginJsonTokenTempDto>(str);
#endregion
//映射登录信息
r.UserInfo = _mapper.Map<UserInfoDto>(entity);
_logger.LogInformation($"登录信息用户ID->{entity.uc_id}");
//HTTP请求获取登录信息人员客户供应商公司
var loginRequest = new LoginSingleRequest()
{
UserId = entity.uc_id,
SupplierId = entity.supplier_id ?? 0,
CustomerId = entity.customer_id ?? 0
};
var loginResponse_result = await _singleDataService.GetSingleDataNoCache<Result<LoginSingleResponse>, LoginSingleRequest, SingleLoginAction>
(loginRequest, SingleLoginAction.All, 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.Supplier != null)
r.UserInfo.SupplierName = loginResponse.Supplier.Name;
if (loginResponse.Customer != null)
r.UserInfo.CustomerName = loginResponse.Customer.Name;
if (loginResponse.Staff != null)
{
r.UserInfo.StaffId = loginResponse.Staff.Id;
staffName = loginResponse.Staff.Name;
}
if (loginResponse.Company != null)
r.UserInfo.CompanyName = loginResponse.Company.Name;
}
r.UserInfo.UcId = entity.uc_id;
r.UserInfo.SeesionId = _loginDto?.uc_sessid;
r.UserInfo.CompanyId = entity.company_id.Value;
r.UserInfo.Identity = entity.identity;
r.UserInfo.OrgId = entity.org_id;
r.UserInfo.CustomerId = entity.customer_id;
r.UserInfo.SupplierId = entity.supplier_id;
r.SignedIn = true;
_logger.LogInformation($"登录信息:用户人员信息->{staffName}{r.UserInfo.StaffId}),公司名称->{r.UserInfo.CompanyName}");
//登录后缓存登录的用户信息和token信息
var loginInfo = new LoginInDto();
loginInfo.UserInfo = r.UserInfo;
loginInfo.TokenInfo = token;
var ops_login_time = token.Expired.AddDays(1) - DateTime.Now;//用于正式
_redisClientService.SetStringKey<LoginInDto>($"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<LoginInDto>.ReFailure("授权失败,请重新登录", 401);
return Result<LoginInDto>.ReSuccess(r);
}
else
{
var errno_text = "登陆失败:" + jObject["errmsg"];
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)
{
_logger.LogInformation("用户信息登录:" + errno_text);
return Result<LoginInDto>.ReFailure("拒绝用户证书试图访问此web站点请与站点管理员联系以建立用户证书权限", 403);
}
else
{
return Result<LoginInDto>.ReFailure(jObject["errmsg"], jObject["errno"]);
}
}
}
catch (Exception ex)
{
return Result<LoginInDto>.ReFailure("授权失败,请重新登录", 401);
}
}
/// <summary>
/// 获取单点用户信息
/// </summary>
/// <param name="username"></param>
/// <param name="password"></param>
/// <returns></returns>
public async Task<Result<LoginInDto>> 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<LoginTempV2Dto>(datajson);
#region
string enptStr = _loginDto.encrypted_data;
List<string> enptlist = enptStr.Trim().Split(',').ToList();
string str = RSA.DecryptSection(_soaOptions.PrivateKey, enptlist);
var entity = JsonConvert.DeserializeObject<LoginJsonTokenV3TempDto>(str);
#endregion
//映射登录信息
var userInfo_v3 = _mapper.Map<UserInfoV3Dto>(entity);
_logger.LogInformation($"登录信息用户ID->{entity.id}");
//HTTP请求获取登录信息人员客户供应商公司
var loginRequest = new LoginSingleRequest()
{
UserId = entity.id,
};
var loginResponse_result = await _singleDataService.GetSingleDataNoCache<Result<SingleDataResponse>, 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.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;
var ops_login_time = token.Expired.AddDays(1) - DateTime.Now;//用于正式
_redisClientService.SetStringKey<LoginInDto>($"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<LoginInDto>.ReFailure("授权失败,请重新登录", 401);
return Result<LoginInDto>.ReSuccess(r);
}
else
{
var errno_text = "登陆失败:" + jObject["errmsg"];
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<LoginInDto>.ReFailure("拒绝用户证书试图访问此web站点请与站点管理员联系以建立用户证书权限", 403);
}
else
{
return Result<LoginInDto>.ReFailure(jObject["errmsg"], jObject["errno"]);
}
}
}
catch (Exception ex)
{
_logger.LogInformation("登录错误信息:" + ex.Message);
return Result<LoginInDto>.ReFailure("授权失败,请重新登录", 401);
}
}
/// <summary>
/// 登录退出
/// </summary>
/// <returns></returns>
public async Task<Result> LoginOutAsync(LoginOutDto dto)
{
_logger.LogInformation("dto_SessionId:" + dto.SessionId);
//2.请求PHP单点登出接口
JsonObject reqData = new JsonObject();
reqData.Add("app_id", _soaOptions.AppId);
reqData.Add("app_secret", _soaOptions.AppSecret);
reqData.Add("access_token", dto.AccessToken);
string result = _httpClientHelp.PostHttp(_soaOptions.Url + "/uc/authorize/signin_out", reqData, true, dto.SessionId);
_logger.LogInformation("退出登录返回:" + result);
var jObject = JsonObject.Parse(result);
if (jObject["errno"] == 0)
{
//设置本地token的缓存为黑名单的token做存储
await CacheOutToken(dto);
return Result.ReSuccess();
}
else
{
return Result.ReFailure(BaseResultCodes.UnAuthorized);
}
}
/// <summary>
/// 刷新token
/// </summary>
/// <returns></returns>
public async Task<Result<LoginInDto>> RefreshToken(string Token, string RefreshToken)
{
_logger.LogInformation("RefreshToken:" + RefreshToken);
//1.根据旧token 找到登录对象
var loginInfo = _redisClientService.GetStringKey<LoginInDto>($"wms_login_{Token}");
//2.请求PHP单点登出接口
JsonObject reqData = new JsonObject();
reqData.Add("app_id", _soaOptions.AppId);
reqData.Add("app_secret", _soaOptions.AppSecret);
reqData.Add("refresh_token", RefreshToken);
string result = _httpClientHelp.PostHttp(_soaOptions.Url + "/uc/authorize/refresh_token", reqData, true, Token);
var jObject = JsonObject.Parse(result);
LoginInDto r = new LoginInDto();
r.UserInfo = new UserInfoDto();
r.TokenInfo = new AccessTokenDto();
if (jObject["errno"] == 0)
{
string datajson = jObject["data"].ToString();
var _loginDto = JsonConvert.DeserializeObject<LoginTempDto>(datajson);
r.UserInfo = loginInfo.UserInfo;
r.SignedIn = true;
var token = await CreateToken(loginInfo.UserInfo, _loginDto, Token);
r.TokenInfo = token;
loginInfo.TokenInfo = token;
var ops_login_time = token.Expired.AddDays(1) - DateTime.Now;//用于正式
_redisClientService.SetStringKey<LoginInDto>($"wms_login_{token.Token}", loginInfo, ops_login_time);
return Result<LoginInDto>.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<LoginInDto>.ReFailure(jObject["errmsg"], jObject["errno"]);
}
}
/// <summary>
/// 单点退出通知token失效
/// </summary>
/// <param name="ucid"></param>
/// <param name="token"></param>
/// <param name="expires_in"></param>
/// <returns></returns>
public async Task LoginOutSingleAsync(int ucid, string token, int expires_in)
{
await Task.Run(() =>
{
var cache_token = _redisClientService.GetStringKey($"wms_black_token_{ucid}");
if (string.IsNullOrEmpty(cache_token))
{
DateTime expires_time = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1)).AddSeconds(expires_in);
var time = new TimeSpan(expires_time.Day, expires_time.Hour, expires_time.Minute, expires_time.Second, expires_time.Millisecond);
_redisClientService.SetStringKey($"wms_black_token_{ucid}", token, time);
this.RemoveLoginInfo(token);
}
});
}
/// <summary>
/// 单点退出通知token失效
/// </summary>
/// <param name="SeesionId">这个是单点传过来的SeesionId</param>
/// <returns></returns>
public async Task LoginOutSingleAsync(string SeesionId)
{
var logininfo = _redisClientService.GetStringKey<LoginInDto>($"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);
}
}
});
}
/// <summary>
/// 缓存退出的token
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
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);
}
});
}
/// <summary>
/// 获取登录后的信息
/// </summary>
/// <param name="authorization"></param>
/// <returns></returns>
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<LoginInDto>($"wms_login_{token}");
return logininfo;
}
/// <summary>
/// 移除登录后的用户信息
/// </summary>
/// <param name="token"></param>
private void RemoveLoginInfo(string token)
{
if (!string.IsNullOrEmpty(token))
{
var info = _redisClientService.GetStringKey<LoginInDto>($"wms_login_{token}");
if (info != null)
{
_redisClientService.RemoveStringKey($"wms_login_{token}");
}
}
}
/// <summary>
/// 单点-在线接口
/// </summary>
/// <param name="sessionId"></param>
/// <returns></returns>
public async Task<Result> Online(string sessionId)
{
var request = new { PHPSESSID = sessionId };
string result = _httpClientHelp.PostHttpNoData(_soaOptions.Url + "/uc/user/online.html?app_id=" + _soaOptions.AppId, sessionId);
return Result.ReSuccess();
}
/// <summary>
/// 单点-下线接口
/// </summary>
/// <param name="sessionId"></param>
/// <returns></returns>
public async Task<Result> Offline(string sessionId)
{
var request = new { PHPSESSID = sessionId };
string result = _httpClientHelp.PostHttpNoData(_soaOptions.Url + "/uc/user/offline.html?app_id=" + _soaOptions.AppId, sessionId);
return Result.ReSuccess();
}
}
}