更新支付、转账、用户控制、新增证书

development
温天培 10 months ago
parent 32a96c59dc
commit bcdac0394c

@ -0,0 +1,23 @@
using System;
using SqlSugar;
using System.ComponentModel;
using GDZZ.Core.Entity;
namespace GDZZ.Application
{
/// <summary>
/// 业务用户关联表
/// </summary>
[SugarTable("baseuser_sysuser_scope")]
[Description("业务用户关联表")]
public class UserScope
{
/// <summary>
/// 业务用户ID
/// </summary>
public long BaseUserID { get; set; }
/// <summary>
/// 系统用户ID
/// </summary>
public long SysUserID { get; set; }
}
}

@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GDZZ.Application.Enum
{
public enum MerchantErrorEnum
{
/// <summary>
/// 系统错误
/// </summary>
[Description("系统错误")] SYSTEM_ERROR = 0,
/// <summary>
/// 商户号和appid没有绑定关系
/// </summary>
[Description("商户号和appid没有绑定关系")] APPID_MCHID_NOT_MATCH = 1,
/// <summary>
/// 系统错误
/// </summary>
[Description("参数错误")] PARAM_ERROR = 2,
/// <summary>
/// 系统错误
/// </summary>
[Description("请求参数符合参数格式,但不符合业务规则")] INVALID_REQUEST = 3,
/// <summary>
/// 系统错误
/// </summary>
[Description("商户信息不合法")] NO_AUTH = 4,
/// <summary>
/// 系统错误
/// </summary>
[Description("资金不足")] NOT_ENOUGH = 5,
/// <summary>
/// 系统错误
/// </summary>
[Description("商户账户付款受限")] ACCOUNTERROR = 6,
/// <summary>
/// 系统错误
/// </summary>
[Description("超出商户单日转账额度")] QUOTA_EXCEED =7,
/// <summary>
/// 系统错误
/// </summary>
[Description("频率超限")] FREQUENCY_LIMITED = 0,
}
}

@ -7,6 +7,8 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Flurl" Version="4.0.0" />
<PackageReference Include="Flurl.Http" Version="4.0.2" />
<PackageReference Include="Senparc.CO2NET.WebApi" Version="1.3.3.7" /> <PackageReference Include="Senparc.CO2NET.WebApi" Version="1.3.3.7" />
<PackageReference Include="Senparc.NeuChar.App" Version="1.1.4.5" /> <PackageReference Include="Senparc.NeuChar.App" Version="1.1.4.5" />
<PackageReference Include="Senparc.NeuChar.AspNet" Version="1.1.3.5" /> <PackageReference Include="Senparc.NeuChar.AspNet" Version="1.1.3.5" />

@ -804,6 +804,21 @@
求职联系费用 求职联系费用
</summary> </summary>
</member> </member>
<member name="T:GDZZ.Application.UserScope">
<summary>
业务用户关联表
</summary>
</member>
<member name="P:GDZZ.Application.UserScope.BaseUserID">
<summary>
业务用户ID
</summary>
</member>
<member name="P:GDZZ.Application.UserScope.SysUserID">
<summary>
系统用户ID
</summary>
</member>
<member name="T:GDZZ.Application.Enum.BannerEnum"> <member name="T:GDZZ.Application.Enum.BannerEnum">
<summary> <summary>
活动类型 活动类型
@ -834,6 +849,51 @@
解除合作 解除合作
</summary> </summary>
</member> </member>
<member name="F:GDZZ.Application.Enum.MerchantErrorEnum.SYSTEM_ERROR">
<summary>
系统错误
</summary>
</member>
<member name="F:GDZZ.Application.Enum.MerchantErrorEnum.APPID_MCHID_NOT_MATCH">
<summary>
商户号和appid没有绑定关系
</summary>
</member>
<member name="F:GDZZ.Application.Enum.MerchantErrorEnum.PARAM_ERROR">
<summary>
系统错误
</summary>
</member>
<member name="F:GDZZ.Application.Enum.MerchantErrorEnum.INVALID_REQUEST">
<summary>
系统错误
</summary>
</member>
<member name="F:GDZZ.Application.Enum.MerchantErrorEnum.NO_AUTH">
<summary>
系统错误
</summary>
</member>
<member name="F:GDZZ.Application.Enum.MerchantErrorEnum.NOT_ENOUGH">
<summary>
系统错误
</summary>
</member>
<member name="F:GDZZ.Application.Enum.MerchantErrorEnum.ACCOUNTERROR">
<summary>
系统错误
</summary>
</member>
<member name="F:GDZZ.Application.Enum.MerchantErrorEnum.QUOTA_EXCEED">
<summary>
系统错误
</summary>
</member>
<member name="F:GDZZ.Application.Enum.MerchantErrorEnum.FREQUENCY_LIMITED">
<summary>
系统错误
</summary>
</member>
<member name="F:GDZZ.Application.Enum.ResumeTypeEnum.Hot"> <member name="F:GDZZ.Application.Enum.ResumeTypeEnum.Hot">
<summary> <summary>
热招 热招
@ -1667,7 +1727,7 @@
退款消息 退款消息
</summary> </summary>
</member> </member>
<member name="P:GDZZ.Application.TransferInput.MerchantID"> <member name="P:GDZZ.Application.TransferInput.OpenID">
<summary> <summary>
商户ID 商户ID
</summary> </summary>
@ -4260,16 +4320,16 @@
JsApiPay 的摘要说明 JsApiPay 的摘要说明
</summary> </summary>
</member> </member>
<member name="M:JsApiPay.WxV3PostJson(System.String,System.String,System.String,System.String)"> <member name="M:JsApiPay.WxV3PostJson(System.String,System.String,System.String,System.String,System.String)">
<summary> <summary>
V3版本请求接口 V3版本请求接口
</summary> </summary>
<param name="url">微信的接口地址</param> <param name="url">微信的接口地址</param>
<param name="postData">post请求的数据json格式 </param> <param name="postData">post请求的数据json格式 </param>
<param name="privateKey">apiclient_key.pem中的内容不要-----BEGIN PRIVATE KEY----- -----END PRIVATE KEY-----</param> <param name="privateKey">apiclient_key.pem中的内容不要-----BEGIN PRIVATE KEY----- -----END PRIVATE KEY-----</param>
<param name="merchantId">发起请求的商户(包括直连商户、服务商或渠道商)的商户号 mchid</param> <param name="mchId">发起请求的商户(包括直连商户、服务商或渠道商)的商户号 mchid</param>
<param name="serialNo">商户证书号</param> <param name="serialNo">商户证书号</param>
<param name="method"></param> <param name="hostting"></param>
<returns></returns> <returns></returns>
</member> </member>
</members> </members>

@ -57,10 +57,10 @@ namespace GDZZ.Application.Help
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[NonAction] [NonAction]
public async Task DelLiveHistoryService(long UserID) public async Task<bool> DelLiveHistoryService(long UserID)
{ {
string cacheKey = SystemConst.LIVE_HISTORYLIST + $"{UserID}"; string cacheKey = SystemConst.LIVE_HISTORYLIST + $"{UserID}";
await _redisCache.DelAsync(cacheKey); return await _redisCache.DelAsync(cacheKey)>0;
} }
#endregion #endregion

@ -13,7 +13,7 @@ namespace GDZZ.Application.Help
public interface ICacheService public interface ICacheService
{ {
#region 聊天接口 #region 聊天接口
Task DelLiveHistoryService(long UserID); Task<bool> DelLiveHistoryService(long UserID);
Task<List<LiveHistoryLists>> GetLiveHistoryService(long UserID); Task<List<LiveHistoryLists>> GetLiveHistoryService(long UserID);
Task SetLiveHistoryService(long UserID, List<LiveHistoryLists> liveMessageLists); Task SetLiveHistoryService(long UserID, List<LiveHistoryLists> liveMessageLists);
#endregion #endregion

@ -33,6 +33,8 @@ namespace GDZZ.Application.Service.Auth
#region 仓储 #region 仓储
private readonly SqlSugarRepository<BaseUser> Baseuser; // wx用户仓储 private readonly SqlSugarRepository<BaseUser> Baseuser; // wx用户仓储
private readonly SqlSugarRepository<SysUser> _sysUserRep; // 用户表仓储 private readonly SqlSugarRepository<SysUser> _sysUserRep; // 用户表仓储
private readonly SqlSugarRepository<UserScope> UserScope; //用户业务关联仓储 _
private readonly SqlSugarRepository<SysTenant> _sysTenantRep; //租户仓储 private readonly SqlSugarRepository<SysTenant> _sysTenantRep; //租户仓储
private readonly SqlSugarRepository<SeIF> Self; //职业仓储 private readonly SqlSugarRepository<SeIF> Self; //职业仓储
private readonly SqlSugarRepository<Company> CompanyRep; private readonly SqlSugarRepository<Company> CompanyRep;
@ -59,6 +61,7 @@ namespace GDZZ.Application.Service.Auth
public AuthService( public AuthService(
IOptions<OAuthOptions> options, IOptions<OAuthOptions> options,
SqlSugarRepository<UserScope> UserScope,
SqlSugarRepository<BaseUser> Baseuser, SqlSugarRepository<BaseUser> Baseuser,
SqlSugarRepository<SysTenant> sysTenantRep, SqlSugarRepository<SysTenant> sysTenantRep,
SqlSugarRepository<SysUser> sysUserRep, SqlSugarRepository<SysUser> sysUserRep,
@ -75,6 +78,7 @@ namespace GDZZ.Application.Service.Auth
IEventPublisher eventPublisher, IEventPublisher eventPublisher,
IHttpContextAccessor httpContextAccessor) IHttpContextAccessor httpContextAccessor)
{ {
this.UserScope = UserScope;
this.CompanyRep= CompanyRep; this.CompanyRep= CompanyRep;
this._eventPublisher= eventPublisher; this._eventPublisher= eventPublisher;
this._sysUserRep = sysUserRep; this._sysUserRep = sysUserRep;
@ -102,133 +106,144 @@ namespace GDZZ.Application.Service.Auth
public async Task<AuthUserOut> SignInAsync(PhoneModel phoneModel) public async Task<AuthUserOut> SignInAsync(PhoneModel phoneModel)
{ {
AuthUserOut authUserOut = new AuthUserOut(); AuthUserOut authUserOut = new AuthUserOut();
Company company = new Company(); Company company = new Company();
try
//读取凭证
var tokenModel = await this._wechatOAuth.GetCode2SessionAsync(phoneModel.Code);
//解析电话
var phoneInfo = MiniProgramUtil.AESDecrypt(phoneModel.EncryptedDataStr, tokenModel.SessionKey, phoneModel.Iv);
//查询系统用户
var sysUser = this._sysUserRep.AsQueryable()
.Filter("TenantId", true)
.First(x => x.Phone == phoneInfo.PhoneNumber);
var wxUser = await this.Baseuser.AsQueryable()
.Filter("TenantId", true)
.Where(x => x.OpenID == tokenModel.OpenId).SingleAsync();
//账号不存在 生成系统账号
if (sysUser.IsEmpty())
{ {
sysUser = await this._sysUserRep.InsertReturnEntityAsync(new SysUser() this.UserScope.BeginTran(); //开启事务
//读取凭证
var tokenModel = await this._wechatOAuth.GetCode2SessionAsync(phoneModel.Code);
//解析电话
var phoneInfo = MiniProgramUtil.AESDecrypt(phoneModel.EncryptedDataStr, tokenModel.SessionKey, phoneModel.Iv);
//系统用户
var sysUser = this._sysUserRep.AsQueryable()
.Filter("TenantId", true)
.First(x => x.Phone == phoneInfo.PhoneNumber);
//业务用户
var wxUser = await this.Baseuser.AsQueryable()
.Filter("TenantId", true)
.Where(x => x.OpenID == tokenModel.OpenId).SingleAsync();
//账号不存在 生成系统账号
if (sysUser.IsEmpty())
{ {
Account = phoneInfo.PurePhoneNumber, //wxUser = await this.UserScope.InsertAsync(new UserScope)
AdminType = AdminType.None, sysUser = await this._sysUserRep.InsertReturnEntityAsync(new SysUser()
Avatar = "https://gdzongzhi.com/assets/img/logo.png", {
Birthday = DateTime.Now, Account = phoneInfo.PurePhoneNumber,
CreatedTime = DateTime.Now, AdminType = AdminType.None,
CreatedUserId = null, Avatar = "https://gdzongzhi.com/assets/img/logo.png",
CreatedUserName = null, Birthday = DateTime.Now,
Sex = Gender.UNKNOWN, CreatedTime = DateTime.Now,
Status = CommonStatus.ENABLE, CreatedUserId = null,
Email = null, CreatedUserName = null,
IsDeleted = false, Sex = Gender.UNKNOWN,
Name = phoneInfo.PhoneNumber, Status = CommonStatus.ENABLE,
Password = MD5Encryption.Encrypt("123456"), Email = null,
TenantId = 392820661919813, IsDeleted = false,
Phone = phoneInfo.PhoneNumber, Name = phoneInfo.PhoneNumber,
NickName = "", Password = MD5Encryption.Encrypt("123456"),
Tel = null, TenantId = 392820661919813,
}); Phone = phoneInfo.PhoneNumber,
} NickName = "",
Tel = null,
if (wxUser.IsEmpty()) });
{ }
wxUser = await this.Baseuser.InsertReturnEntityAsync(new BaseUser()
if (wxUser.IsEmpty())
{ {
UnionId = tokenModel.Unionid, wxUser = await this.Baseuser.InsertReturnEntityAsync(new BaseUser()
CreatedUserId = sysUser.Id, {
CreatedTime = DateTime.Now, UnionId = tokenModel.Unionid,
CreatedUserName = sysUser.Name, CreatedUserId = sysUser.Id,
AvatarUrl = "https://gdzongzhi.com/assets/img/logo.png", CreatedTime = DateTime.Now,
Status = (int)CommonStatus.ENABLE, CreatedUserName = sysUser.Name,
OpenID = tokenModel.OpenId, AvatarUrl = "https://gdzongzhi.com/assets/img/logo.png",
UserName = phoneModel.Phone.ToString(), Status = (int)CommonStatus.ENABLE,
}); OpenID = tokenModel.OpenId,
} UserName = phoneModel.Phone.ToString(),
//区分账号类型 });
switch (phoneModel.LogInType) }
{ //区分账号类型
case (int)UserEnum.JOB: switch (phoneModel.LogInType)
wxUser.Type = (int)UserEnum.JOB; {
await this.Baseuser.UpdateAsync(wxUser); case (int)UserEnum.JOB:
break; wxUser.Type = (int)UserEnum.JOB;
case (int)UserEnum.HEADHUNTERS: await this.Baseuser.UpdateAsync(wxUser);
wxUser.Type = (int)UserEnum.HEADHUNTERS; break;
await this.Baseuser.UpdateAsync(wxUser); case (int)UserEnum.HEADHUNTERS:
break; wxUser.Type = (int)UserEnum.HEADHUNTERS;
case (int)UserEnum.ADVERTISE: await this.Baseuser.UpdateAsync(wxUser);
wxUser.Type = (int)UserEnum.ADVERTISE; break;
await this.Baseuser.UpdateAsync(wxUser); case (int)UserEnum.ADVERTISE:
//获取公司信息 wxUser.Type = (int)UserEnum.ADVERTISE;
company = await this.CompanyRep.FirstOrDefaultAsync(x => x.Id == wxUser.CompanyID); await this.Baseuser.UpdateAsync(wxUser);
authUserOut.companyDto = company.Adapt<CompanyDto>(); //获取公司信息
break; company = await this.CompanyRep.FirstOrDefaultAsync(x => x.Id == wxUser.CompanyID);
default: authUserOut.companyDto = company.Adapt<CompanyDto>();
break; break;
} default:
break;
}
if (wxUser.IsEmpty() || sysUser.IsEmpty()) if (wxUser.IsEmpty() || sysUser.IsEmpty())
throw Oops.Oh(ErrorCode.xg1002); throw Oops.Oh(ErrorCode.xg1002);
//判断是否存在邀请 var userc = await this.UserScope.FirstOrDefaultAsync(x => x.BaseUserID == wxUser.Id && x.SysUserID == sysUser.Id);
if(phoneModel.Scene != null) if (userc.IsNullOrZero())
{
//判断当前用户是否被邀请过
var invi = await this.invitaitionRey.FirstOrDefaultAsync(x => x.UserID == UserManager.UserId);
if (invi.IsNullOrZero())
{ {
var invres = await this.invitaitionRey.FirstOrDefaultAsync(x => x.InviteID == phoneModel.Scene); await this.UserScope.InsertAsync(new UserScope()
//未被邀请
var invrey = await this.invitaitionRey.InsertAsync(new InviteUserPos()
{ {
UserID = UserManager.UserId, SysUserID = sysUser.Id,
InviteUserID = (long)phoneModel.Scene, BaseUserID = wxUser.Id,
InviteID = invres.InviteID
}); });
if (invrey > 0)
}
//判断是否存在邀请
if (phoneModel.Scene != null)
{
//判断当前用户是否被邀请过
var invi = await this.invitaitionRey.FirstOrDefaultAsync(x => x.UserID == UserManager.UserId);
if (invi.IsNullOrZero())
{ {
//附加奖励给邀请人 var invres = await this.invitaitionRey.FirstOrDefaultAsync(x => x.InviteID == phoneModel.Scene);
UtilService utilService = new UtilService(this.rechargeRep); //未被邀请
utilService.Reward((long)phoneModel.Scene, 1); var invrey = await this.invitaitionRey.InsertAsync(new InviteUserPos()
{
UserID = UserManager.UserId,
InviteUserID = (long)phoneModel.Scene,
InviteID = invres.InviteID
});
if (invrey > 0)
{
//附加奖励给邀请人
UtilService utilService = new UtilService(this.rechargeRep);
utilService.Reward((long)phoneModel.Scene, 1);
}
} }
} }
} var Self = await this.Self.FirstOrDefaultAsync(x => x.CreatedUserId == sysUser.Id);
var Self = await this.Self.FirstOrDefaultAsync(x => x.CreatedUserId == sysUser.Id);
// 获取加密后的密码 // 获取加密后的密码
var encryptPassword = MD5Encryption.Encrypt(sysUser.Password); var encryptPassword = MD5Encryption.Encrypt(sysUser.Password);
// 验证账号是否被冻结 // 验证账号是否被冻结
if (sysUser.Status == CommonStatus.DISABLE) if (sysUser.Status == CommonStatus.DISABLE)
throw Oops.Oh(ErrorCode.D1017); throw Oops.Oh(ErrorCode.D1017);
//获取对应租户 //获取对应租户
var tenant = this._sysTenantRep.Single(sysUser.TenantId); var tenant = this._sysTenantRep.Single(sysUser.TenantId);
if (tenant.IsNullOrZero()) if (tenant.IsNullOrZero())
throw Oops.Oh(ErrorCode.F1001); throw Oops.Oh(ErrorCode.F1001);
// 生成Token令牌 // 生成Token令牌
authUserOut.Token = JWTEncryption.Encrypt(new Dictionary<string, object> authUserOut.Token = JWTEncryption.Encrypt(new Dictionary<string, object>
{ {
{ClaimConst.CLAINM_USERID, sysUser.Id}, {ClaimConst.CLAINM_USERID, sysUser.Id},
{ClaimConst.TENANT_ID, sysUser.TenantId}, {ClaimConst.TENANT_ID, sysUser.TenantId},
@ -239,31 +254,38 @@ namespace GDZZ.Application.Service.Auth
{ ClaimConst.CLAINM_TENANT_NAME, tenant.Name }, { ClaimConst.CLAINM_TENANT_NAME, tenant.Name },
}); });
// 设置Swagger自动登录 // 设置Swagger自动登录
_httpContextAccessor.HttpContext.SigninToSwagger(authUserOut.Token); _httpContextAccessor.HttpContext.SigninToSwagger(authUserOut.Token);
// 生成刷新Token令牌 // 生成刷新Token令牌
var refreshToken = JWTEncryption.GenerateRefreshToken(authUserOut.Token, 30); var refreshToken = JWTEncryption.GenerateRefreshToken(authUserOut.Token, 30);
// 设置刷新Token令牌 // 设置刷新Token令牌
_httpContextAccessor.HttpContext.Response.Headers["x-access-token"] = refreshToken; _httpContextAccessor.HttpContext.Response.Headers["x-access-token"] = refreshToken;
var httpContext = App.HttpContext; var httpContext = App.HttpContext;
await _eventPublisher.PublishAsync(new ChannelEventSource("Update:UserLoginInfo", await _eventPublisher.PublishAsync(new ChannelEventSource("Update:UserLoginInfo",
new SysUser { Id = sysUser.Id, LastLoginIp = httpContext.GetLocalIpAddressToIPv4(), LastLoginTime = DateTime.Now })); new SysUser { Id = sysUser.Id, LastLoginIp = httpContext.GetLocalIpAddressToIPv4(), LastLoginTime = DateTime.Now }));
authUserOut.Avatar = sysUser.Avatar;
authUserOut.Phone = sysUser.Phone;
authUserOut.Sex = sysUser.Sex;
authUserOut.UserId = sysUser.Id;
authUserOut.UserName = sysUser.Name;
authUserOut.Self = Self.IsEmpty() ? null : Self.Name;
authUserOut.Type = (UserEnum)wxUser.Type;
authUserOut.OpenID = tokenModel.OpenId;
authUserOut.Tenant = tenant.Adapt<TenantOutput>();
authUserOut.Describe = wxUser.Describe;
await this.cacheService.SetUserInfoAsync(authUserOut, authUserOut.UserId);
this.UserScope.CurrentCommitTran();
}
catch (Exception)
{
this.UserScope.CurrentRollbackTran();
throw;
}
authUserOut.Avatar = sysUser.Avatar;
authUserOut.Phone = sysUser.Phone;
authUserOut.Sex = sysUser.Sex;
authUserOut.UserId = sysUser.Id;
authUserOut.UserName = sysUser.Name;
authUserOut.Self = Self.IsEmpty() ? null : Self.Name;
authUserOut.Type = (UserEnum)wxUser.Type;
authUserOut.OpenID = tokenModel.OpenId;
authUserOut.Tenant = tenant.Adapt<TenantOutput>();
authUserOut.Describe = wxUser.Describe;
await this.cacheService.SetUserInfoAsync(authUserOut, authUserOut.UserId);
return authUserOut; return authUserOut;
} }

@ -39,11 +39,11 @@ namespace GDZZ.Application
/// <summary> /// <summary>
/// 商户ID /// 商户ID
/// </summary> /// </summary>
public string MerchantID { get; set; } public string OpenID { get; set; }
/// <summary> /// <summary>
/// 转账金额 /// 转账金额
/// </summary> /// </summary>
public dynamic TransferAmount { get; set; } public decimal TransferAmount { get; set; }
} }
} }

@ -133,7 +133,7 @@ namespace GDZZ.Application
/// <summary> /// <summary>
/// 公司ID /// 公司ID
/// </summary> /// </summary>
public long CompanyID { get; set; } public long? CompanyID { get; set; }
} }
} }

@ -80,12 +80,20 @@ namespace GDZZ.Application
public async Task<dynamic> AddLive(AddLiveFriendInput input) public async Task<dynamic> AddLive(AddLiveFriendInput input)
{ {
var baseUser = await this.Baseuser.AsQueryable().Filter("TenantId", true).Where(x => x.CompanyID == input.CompanyID).SingleAsync(); SysUser user = new SysUser();
if (baseUser.IsNullOrZero()) if (input.CompanyID.IsNullOrZero())
throw Oops.Oh(ErrorCode.B1002); {
var user = await this._sysUserRep.Where(x => x.Id == baseUser.CreatedUserId).SingleAsync(); user = await this._sysUserRep.FirstOrDefaultAsync(x => x.Id == input.UserId);
if (user.IsNullOrZero()) if (user.IsNullOrZero())
throw Oops.Oh(ErrorCode.xg1002); throw Oops.Oh(ErrorCode.xg1002);
}
else
{
var buser = await this.Baseuser.FirstOrDefaultAsync(x => x.CompanyID == input.CompanyID);
user = await this._sysUserRep.Where(x => x.Id == buser.CreatedUserId).SingleAsync();
if (user.IsNullOrZero())
throw Oops.Oh(ErrorCode.xg1002);
}
//判断是是好友 //判断是是好友
var fends =await this.liveUserFriend.Where(x => x.FriendID == UserManager.UserId && x.CreatedUserId == user.Id).FirstAsync(); var fends =await this.liveUserFriend.Where(x => x.FriendID == UserManager.UserId && x.CreatedUserId == user.Id).FirstAsync();
@ -111,7 +119,9 @@ namespace GDZZ.Application
await this.liveUserFriend.InsertAsync(item); await this.liveUserFriend.InsertAsync(item);
} }
} }
await this.cacheService.DelLiveHistoryService(UserManager.UserId);
if(!await this.cacheService.DelLiveHistoryService(UserManager.UserId))
throw Oops.Oh(ErrorCode.B1004);
return user; return user;
} }
@ -186,7 +196,6 @@ namespace GDZZ.Application
Id = item.FriendID, Id = item.FriendID,
Index = sysUser.Name.Substring(0, 1), Index = sysUser.Name.Substring(0, 1),
LastSendTime = (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000000, LastSendTime = (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000000,
}; };
//查询聊天记录 //查询聊天记录

@ -0,0 +1,20 @@
using GDZZ.Application.Enum;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GDZZ.Application
{
public class Merchant
{
public string out_batch_no { get; set; }
public string batch_id { get; set; }
public DateTime create_time { get; set; }
public string code { get; set; }
public string message { get; set; }
}
}

@ -6,19 +6,31 @@ using System.Runtime.Serialization;
using System.IO; using System.IO;
using System.Text; using System.Text;
using System.Net; using System.Net;
using Flurl;
using Flurl.Http;
using Furion.Logging; using Furion.Logging;
using SqlSugar; using SqlSugar;
using Enyim.Caching; using Enyim.Caching;
using System.Security.Cryptography; using System.Security.Cryptography;
using static System.Net.Mime.MediaTypeNames;
using Microsoft.Extensions.Hosting.Internal;
using Enyim.Caching.Configuration;
using Furion.RemoteRequest;
using Furion.RemoteRequest.Extensions;
using System.Net.Http;
using System.Threading.Tasks;
using System.Security.Policy;
/// <summary> /// <summary>
///JsApiPay 的摘要说明 ///JsApiPay 的摘要说明
/// </summary> /// </summary>
public static class JsApiPay public class JsApiPay : IHttpDispatchProxy
{ {
public static string WithDrawsToWx(string appid, string mchid, string serialNo, string openID, string partnerTradeNo, decimal totalFee) const string PrivateKey = "App_Data/cert/apiclient_key.pem";
public async Task<string> WithDrawsToWx(string url, string appid, string mchid, string serialNo, string openID, string partnerTradeNo, decimal totalFee, string hostting)
{ {
SortedDictionary<string, object> dic = new SortedDictionary<string, object>(); SortedDictionary<string, object> dic = new SortedDictionary<string, object>();
@ -39,10 +51,7 @@ public static class JsApiPay
list.Add(dic1); list.Add(dic1);
dic.Add("transfer_detail_list", list); dic.Add("transfer_detail_list", list);
var url = "https://api.mch.weixin.qq.com/v3/transfer/batches"; return await WxV3PostJson(url, Newtonsoft.Json.JsonConvert.SerializeObject(dic), mchid, serialNo, hostting); ; ;
string transactionsResponse = WxV3PostJson(url, Newtonsoft.Json.JsonConvert.SerializeObject(dic), mchid, serialNo);
//Log.Info("商户转账到零钱返回:" , transactionsResponse);
return transactionsResponse; ;
} }
/// <summary> /// <summary>
/// V3版本请求接口 /// V3版本请求接口
@ -50,52 +59,49 @@ public static class JsApiPay
/// <param name="url">微信的接口地址</param> /// <param name="url">微信的接口地址</param>
/// <param name="postData">post请求的数据json格式 </param> /// <param name="postData">post请求的数据json格式 </param>
/// <param name="privateKey">apiclient_key.pem中的内容不要-----BEGIN PRIVATE KEY----- -----END PRIVATE KEY-----</param> /// <param name="privateKey">apiclient_key.pem中的内容不要-----BEGIN PRIVATE KEY----- -----END PRIVATE KEY-----</param>
/// <param name="merchantId">发起请求的商户(包括直连商户、服务商或渠道商)的商户号 mchid</param> /// <param name="mchId">发起请求的商户(包括直连商户、服务商或渠道商)的商户号 mchid</param>
/// <param name="serialNo">商户证书号</param> /// <param name="serialNo">商户证书号</param>
/// <param name="method"></param> /// <param name="hostting"></param>
/// <returns></returns> /// <returns></returns>
public static string WxV3PostJson(string url, string postData, string mchId, string serialNo) public async Task<string> WxV3PostJson(string url, string postData, string mchId, string serialNo, string hostting)
{ {
string Authorization = GetAuthorization(url, "POST", postData, mchId, serialNo, hostting);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); var request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST"; request.Method = "POST";
request.ContentType = "application/json;charset=UTF-8"; request.ContentType = "application/json;charset=UTF-8";
request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3100.0 Safari/537.36"; request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3100.0 Safari/537.36";
request.Accept = "application/json"; request.Accept = "application/json";
//Log.Info("发起开始申请商户转账到零钱请求", "发起请求1");
string Authorization = GetAuthorization(url, "POST", postData, mchId, serialNo);
request.Headers.Add("Authorization", Authorization); request.Headers.Add("Authorization", Authorization);
//Log.Info("返回申请商户转账到零钱结果", Authorization); byte[] byteData = System.Text.Encoding.UTF8.GetBytes(postData);
byte[] paramJsonBytes; request.ContentLength = byteData.Length;
paramJsonBytes = System.Text.Encoding.UTF8.GetBytes(postData);
request.ContentLength = paramJsonBytes.Length;
Stream writer; Stream writer;
try try
{ {
writer = request.GetRequestStream(); writer = request.GetRequestStream();
} }
catch (Exception) catch (Exception e)
{ {
writer = null;
Console.Write("连接服务器失败!"); Console.Write("连接服务器失败!");
throw;
} }
writer.Write(paramJsonBytes, 0, paramJsonBytes.Length); writer.Write(byteData, 0, byteData.Length);
writer.Close(); writer.Close();
string responseString = "";
HttpWebResponse response; HttpWebResponse response;
try try
{ {
response = (HttpWebResponse)request.GetResponse(); response = (HttpWebResponse)request.GetResponse();
} }
catch (WebException ex) catch (WebException e)
{ {
response = ex.Response as HttpWebResponse; response = e.Response as HttpWebResponse;
} }
Stream resStream = response.GetResponseStream(); Stream resStream = response.GetResponseStream();
StreamReader reader = new StreamReader(resStream); StreamReader reader = new StreamReader(resStream);
string text = reader.ReadToEnd(); responseString = reader.ReadToEnd();
return text; return responseString;
} }
private static string GetAuthorization(string url, string method, string jsonParame, string mchId, string serialNo) private string GetAuthorization(string url, string method, string jsonParame, string mchId, string serialNo, string hostting)
{ {
var uri = new Uri(url); var uri = new Uri(url);
string urlPath = uri.PathAndQuery; string urlPath = uri.PathAndQuery;
@ -107,8 +113,8 @@ public static class JsApiPay
//Log.Info("请求message", message); //Log.Info("请求message", message);
//string signTxt = Sign(message, privateKey); //string signTxt = Sign(message, privateKey);
string signTxt = Sign(message); string signTxt = Sign(message, hostting);
//Authorization和格式 //Authorization和格式
string authorzationTxt = string.Format("WECHATPAY2-SHA256-RSA2048 mchid=\"{0}\",nonce_str=\"{1}\",timestamp=\"{2}\",serial_no=\"{3}\",signature=\"{4}\"", string authorzationTxt = string.Format("WECHATPAY2-SHA256-RSA2048 mchid=\"{0}\",nonce_str=\"{1}\",timestamp=\"{2}\",serial_no=\"{3}\",signature=\"{4}\"",
@ -122,17 +128,31 @@ public static class JsApiPay
} }
private static string Sign(string message) private string Sign(string message, string hostting)
{ {
string base64X509Cert = "";
string pemPublicCert = Path.Combine(hostting, PrivateKey);
using (FileStream fs = new FileStream(pemPublicCert, FileMode.Open, FileAccess.Read))
{
using (StreamReader sr = new StreamReader(fs))
{
base64X509Cert = sr.ReadToEnd().Trim();
}
}
base64X509Cert = base64X509Cert.Replace("-----BEGIN PRIVATE KEY-----", "").Replace("-----END PRIVATE KEY-----", "").Replace("\r", "").Replace("\n", "");
// NOTE 私钥不包括私钥文件起始的-----BEGIN PRIVATE KEY----- // NOTE 私钥不包括私钥文件起始的-----BEGIN PRIVATE KEY-----
// 亦不包括结尾的-----END PRIVATE KEY----- // 亦不包括结尾的-----END PRIVATE KEY-----
string privateKey = "{你的私钥}";
byte[] keyData = Convert.FromBase64String(privateKey); byte[] keyData = Convert.FromBase64String(base64X509Cert);
var rsa = RSA.Create(); var rsa = RSA.Create();
rsa.ImportPkcs8PrivateKey(keyData, out _); rsa.ImportPkcs8PrivateKey(keyData, out _);
byte[] data = System.Text.Encoding.UTF8.GetBytes(message); byte[] data = System.Text.Encoding.UTF8.GetBytes(message);
return Convert.ToBase64String(rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)); var sigdata = rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
var res = Convert.ToBase64String(sigdata);
return res;
} }
} }

@ -27,6 +27,8 @@ using Senparc.CO2NET.Cache.Redis;
using GDZZ.Core.Service; using GDZZ.Core.Service;
using System.Linq.Dynamic.Core.Tokenizer; using System.Linq.Dynamic.Core.Tokenizer;
using System.Diagnostics; using System.Diagnostics;
using Microsoft.AspNetCore.Hosting;
using Furion.JsonSerialization;
namespace GDZZ.Application.Service.WXPay namespace GDZZ.Application.Service.WXPay
{ {
@ -35,7 +37,7 @@ namespace GDZZ.Application.Service.WXPay
{ {
private readonly IHostingEnvironment hostingEnvironment;
private readonly SqlSugarRepository<BaseUser> Baseuser; // wx用户仓储 private readonly SqlSugarRepository<BaseUser> Baseuser; // wx用户仓储
private readonly SqlSugarRepository<SysUser> _sysUserRep; // 用户表仓储 private readonly SqlSugarRepository<SysUser> _sysUserRep; // 用户表仓储
private readonly SqlSugarRepository<SysTenant> _sysTenantRep; //租户仓储 private readonly SqlSugarRepository<SysTenant> _sysTenantRep; //租户仓储
@ -71,6 +73,7 @@ namespace GDZZ.Application.Service.WXPay
SqlSugarRepository<MiniPayTake> payTakeRep, SqlSugarRepository<MiniPayTake> payTakeRep,
SqlSugarRepository<ReFund> refundRep, SqlSugarRepository<ReFund> refundRep,
WechatOAuth wechatOAuth, WechatOAuth wechatOAuth,
IHostingEnvironment hostingEnvironment,
IHttpContextAccessor _httpContextAccessor, IHttpContextAccessor _httpContextAccessor,
IEventPublisher eventPublisher) IEventPublisher eventPublisher)
{ {
@ -85,6 +88,7 @@ namespace GDZZ.Application.Service.WXPay
this.payTakeRep = payTakeRep; this.payTakeRep = payTakeRep;
this._wechatOAuth = wechatOAuth; this._wechatOAuth = wechatOAuth;
this._oauthConfig = options.Value.SenparcWeixin; this._oauthConfig = options.Value.SenparcWeixin;
this.hostingEnvironment = hostingEnvironment;
this._httpContextAccessor = _httpContextAccessor; this._httpContextAccessor = _httpContextAccessor;
} }
@ -128,6 +132,7 @@ namespace GDZZ.Application.Service.WXPay
public async Task<dynamic> UpBalance(decimal Consume,long? ResumeID) public async Task<dynamic> UpBalance(decimal Consume,long? ResumeID)
{ {
this.balance.CurrentBeginTran();
var comrep = await this.ComsumeRep.Where(x=>x.ResumeID== ResumeID).FirstAsync(); var comrep = await this.ComsumeRep.Where(x=>x.ResumeID== ResumeID).FirstAsync();
if(!comrep.IsNullOrZero()) //已经消费过了 if(!comrep.IsNullOrZero()) //已经消费过了
return ""; return "";
@ -424,19 +429,21 @@ namespace GDZZ.Application.Service.WXPay
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[HttpPost] [HttpPost]
[Route("Mini/v1/GetBalance")] [Route("Mini/v1/MerchantTransfer")]
public async Task<dynamic> MerchantTransfer(TransferInput wxRefundInput) public async Task<dynamic> MerchantTransfer(TransferInput wxRefundInput)
{ {
var hostting = this.hostingEnvironment.ContentRootPath;
//读取商户信息 //读取商户信息
var appid = Config.SenparcWeixinSetting.TenPayV3_AppId; var appid = Config.SenparcWeixinSetting.TenPayV3_AppId;
var mchid = Config.SenparcWeixinSetting.TenPayV3_MchId; var mchid = Config.SenparcWeixinSetting.TenPayV3_MchId;
var serialno = Config.SenparcWeixinSetting.TenPayV3_SerialNumber; var serialno = Config.SenparcWeixinSetting.TenPayV3_SerialNumber;
string partnerTradeNo = "xcx" + DateTime.Now.ToString("yyyyMMddHHmmfff"); string url = string.Format("https://api.mch.weixin.qq.com/v3/transfer/batches");
string result = JsApiPay.WithDrawsToWx(appid, mchid, serialno, wxRefundInput.MerchantID, partnerTradeNo, Convert.ToInt32(wxRefundInput.TransferAmount * 100)); string partnerTradeNo = "tk" + DateTime.Now.ToString("yyyyMMddHHmmfff");
JsApiPay jsApiPay = new JsApiPay();
string result =await jsApiPay.WithDrawsToWx(url, appid, mchid, serialno, wxRefundInput.OpenID, partnerTradeNo,
Convert.ToInt32(wxRefundInput.TransferAmount * 100), hostting);
return result; return result;
} }

@ -244,6 +244,8 @@ public class SenparcWeixinSetting
public string TenPayV3_PrivateKey { get; set; } public string TenPayV3_PrivateKey { get; set; }
public string TenPayV3_SerialNumber { get; set; } public string TenPayV3_SerialNumber { get; set; }
public string TenPayV3_ApiV3Key { get; set; } public string TenPayV3_ApiV3Key { get; set; }
public string TenPayv3_WxTransfer { get; set; }
} }

@ -431,4 +431,10 @@ public enum ErrorCode
/// </summary> /// </summary>
[ErrorCodeItemMetadata("手机已经存在")] [ErrorCodeItemMetadata("手机已经存在")]
B1003, B1003,
/// <summary>
/// 数据删除失败
/// </summary>
[ErrorCodeItemMetadata("数据删除失败")]
B1004,
} }

@ -2620,6 +2620,11 @@
手机已经存在 手机已经存在
</summary> </summary>
</member> </member>
<member name="F:GDZZ.Core.ErrorCode.B1004">
<summary>
数据删除失败
</summary>
</member>
<member name="T:GDZZ.Core.FileExtensionEnum"> <member name="T:GDZZ.Core.FileExtensionEnum">
<summary> <summary>
文件扩展枚举 文件扩展枚举

@ -18,8 +18,6 @@ public static class UserManager
/// </summary> /// </summary>
public static string Account => App.User.FindFirst(ClaimConst.CLAINM_ACCOUNT)?.Value; public static string Account => App.User.FindFirst(ClaimConst.CLAINM_ACCOUNT)?.Value;
/// <summary> /// <summary>
/// 租户ID /// 租户ID
/// </summary> /// </summary>

@ -158,9 +158,9 @@
* 1 * 1
* 2~/App_Data/cert/apiclient_key.pem App_Data * 2~/App_Data/cert/apiclient_key.pem App_Data
*/ */
"TenPayV3_PrivateKey": "#{TenPayV3_PrivateKey}#", // "TenPayV3_PrivateKey": "/App_Data/cert/apiclient_key.pem", //
"TenPayV3_SerialNumber": "56FA7394CDD74ACB0329480EAB7185BE7A2CB081", // "TenPayV3_SerialNumber": "133833F7E1F4083BF191A81938EF25AC659F23D6", //
"TenPayV3_ApiV3Key": "#{TenPayV3_APIv3Key}#", //APIv3 "TenPayV3_ApiV3Key": "ZZRZJKvAstv4SJapStuyHhCOzqrrjSUD", //APIv3
//TenPayV3_WxOpenTenpayNotify TenPayV3_TenpayNotify "WxOpen" //TenPayV3_WxOpenTenpayNotify TenPayV3_TenpayNotify "WxOpen"
"TenPayV3_WxOpenTenpayNotify": "https://admin.gdzongzhi.com/api/Mini/NotifyUrlWxOpen", //http://YourDomainName/TenpayV3/PayNotifyUrlWxOpen "TenPayV3_WxOpenTenpayNotify": "https://admin.gdzongzhi.com/api/Mini/NotifyUrlWxOpen", //http://YourDomainName/TenpayV3/PayNotifyUrlWxOpen

@ -0,0 +1,25 @@
-----BEGIN CERTIFICATE-----
MIIEMTCCAxmgAwIBAgIUEzgz9+H0CDvxkagZOO8lrGWfI9YwDQYJKoZIhvcNAQEL
BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT
FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg
Q0EwHhcNMjQwMTIyMDgyMjIyWhcNMjkwMTIwMDgyMjIyWjCBijETMBEGA1UEAwwK
MTY0MDM2MzE2NzEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMTYwNAYDVQQL
DC3lub/kuJznnIHnurXmmbrkvIHkuJrnrqHnkIblkqjor6LmnInpmZDlhazlj7gx
CzAJBgNVBAYTAkNOMREwDwYDVQQHDAhTaGVuWmhlbjCCASIwDQYJKoZIhvcNAQEB
BQADggEPADCCAQoCggEBAMGnNPWyzoN6ldrf0B8coEu0naNSCJZvXRYKKOi8VH17
uNwbuxdYP4G0rWQC1hSbqc7Qz3iFEW5PqKA2ZqoDBdhFNqZTSVMOcw8Dagz0ya1m
a3EdjXSGp7prHNXRSWQtVGYVPqPmg1qrt+Uptfkd75Z1EmIxDMoN8ERLToOtmfi5
vTWWS0TZ9xaE99qGVirb4yjDr9qrutSCx/C1xNHssAnT3m2x5bYHiOEcDGtVp6iG
DqvUBpLaqSa3IxJlQZSZP3mdrV7i2o8tlw8heSQJ+o7VWWrP0V/Y1CgPhsT0HBK4
PRQRPfpHGv98W5tf+XBPorrjYqBFAc6TpoZHKLTY6BcCAwEAAaOBuTCBtjAJBgNV
HRMEAjAAMAsGA1UdDwQEAwID+DCBmwYDVR0fBIGTMIGQMIGNoIGKoIGHhoGEaHR0
cDovL2V2Y2EuaXRydXMuY29tLmNuL3B1YmxpYy9pdHJ1c2NybD9DQT0xQkQ0MjIw
RTUwREJDMDRCMDZBRDM5NzU0OTg0NkMwMUMzRThFQkQyJnNnPUhBQ0M0NzFCNjU0
MjJFMTJCMjdBOUQzM0E4N0FEMUNERjU5MjZFMTQwMzcxMA0GCSqGSIb3DQEBCwUA
A4IBAQCTh90ch63bv8M0xPwCk31nuM5YZL3TsOxN8ZB+3odVEjY/zWuypSgK2aM7
VuvroBsivAlLKefqw/U0JXw2oHNGveWW9Bq71K2KJmb8E+8yLzF9jae1mwCQmBo0
+r0D2OWDdXKrJ0eFAu4Ug6LYIu7x//JoUW3e0jY+BgiOZgkOl7LdI0bmGHiQ8LMr
g0BgUSWc7TDd9r9UH86Rq9E0leA+5ftIN3QDfpIsxcoKXFG1hlFEj6hHQP25aKS2
ViGl35FrUyOC+/2MAyJqjEpfTGOrX3s5HyXDyM19Qqd+oCiLjc0vblWY0Zk8Y22a
DIzWjsG1cpBTaRqxkLaquCkyR26G
-----END CERTIFICATE-----

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDBpzT1ss6DepXa
39AfHKBLtJ2jUgiWb10WCijovFR9e7jcG7sXWD+BtK1kAtYUm6nO0M94hRFuT6ig
NmaqAwXYRTamU0lTDnMPA2oM9MmtZmtxHY10hqe6axzV0UlkLVRmFT6j5oNaq7fl
KbX5He+WdRJiMQzKDfBES06DrZn4ub01lktE2fcWhPfahlYq2+Mow6/aq7rUgsfw
tcTR7LAJ095tseW2B4jhHAxrVaeohg6r1AaS2qkmtyMSZUGUmT95na1e4tqPLZcP
IXkkCfqO1Vlqz9Ff2NQoD4bE9BwSuD0UET36Rxr/fFubX/lwT6K642KgRQHOk6aG
Ryi02OgXAgMBAAECggEACBBXYzfL46uyG8ggGXuOrThbLBbZZrJCdQ19QJu/BO6m
9vtsof85vcPxSG3ZzkfhHUySpxkbbbWBdxJs2f2AO84+BVUIg53haqmgu+Nhlofi
R3aMkmKdD2UwcTLi1HoSvqF510ddBuSJptBC1JnLhT9gwZf7SVqlO6LLJS6Qb8vx
hMqNlvG3EqBVGSTuE8mTjcga3lmI9eAxz8rL9sZ59lj17k2JTxW6/Q3QjeTRqIpA
UTm+SOjVYn++2kHB3Ix8RYD5vClsZ7BpMS0f3fko6qt/SuRHS0wZF2RoELia+ohv
AyON+jKGSGRVivCiMPISDE7UGaA/cxKrolTok63QWQKBgQD8v14vWxZVp15VPosb
1quBUDajQLBjfNIifoU1Aqc7VD2zLJ79LN7Pngv84p55TAS3+MTcu/elYGeUeZuS
X/JexTJmSE30FtmGhpCuf/9VXyj7rN6sYbJkj+1ENFFv/qM0NBxagk/aVewM+PHs
tIetibw+qZ0iiabnSUrqBMMVkwKBgQDEJSm4hkzGdL3I1oOyVbju/gMXcMM3IMxZ
RpsmUQ8qhjid9KvBvC/AmWJFyDAkAkVownAcvSwoJAMSNUuApghEPDqRvvNnoc72
lmtbwF5s6veyadZMVnrTc/ipFZdZg9ya+Qs0Kocbnceo2fJ+R5+HBtt+Wd8GE0oc
24//+C+17QKBgQCFdsxWd2QI4POYUgmFLsur4l6nwG4kavJP0r2mq3sBgk9+gO6H
xJz3x36PEGAcrz7CozPZV8zC4HBx3/F9zvqefsVJa572aOZ++ioGa4K6YyCyHawM
HR7lqXbiEDp8yFsIIwhh5vQh2ENo6kBd/Uq0Icps0IYwib2/3l0XzGHzzwKBgEsa
h70V/3PF451xNgAk/qjULk7daIJFVrmgZWvogcwglLE2rEWETyyKDqz1mClRjU4t
lUwLy0qbb2mbaouaB3RJM4v297BorpyQwA7ju8QsvCdeiyWzv1gUAdSMZeVqrh/Q
2E9jMVSLt5WZzlY4CodjQsxAkTr8S9Z848h5OZuJAoGBAKaaRH/9FY7igN5okg6s
4GkoxvhOtUZ2quMCK79xKnq7SaMXz07qEhBK/a9ajYvzlbOCw9ZcX3pe641IbE+K
03Fo7Uy/dJEtKE9rqA0lefGR9GpMbb6PdeHh9RvOKftMhrk8p8rL/GwUc2eFzgse
BfWBXzr2mpCy3arBimmjeyx/
-----END PRIVATE KEY-----
Loading…
Cancel
Save