You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

495 lines
24 KiB

using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using SKIT.FlurlHttpClient.Wechat.TenpayV3;
using SKIT.FlurlHttpClient.Wechat.TenpayV3.Events;
using SKIT.FlurlHttpClient.Wechat.TenpayV3.Models;
using SKIT.FlurlHttpClient.Wechat.TenpayV3.Settings;
using System.Text;
using Zncy.CloudCar.WeChat.Service.Options;
using Zncy.CloudCar.WeChat.Service.Services.HttpClients;
using Znyc.CloudCar.Auth.HttpContextUser;
using Znyc.CloudCar.Caching;
using Znyc.CloudCar.Configuration;
using Znyc.CloudCar.IRepository.CardIntro;
using Znyc.CloudCar.IRepository.Order;
using Znyc.CloudCar.IRepository.PaymentRecord;
using Znyc.CloudCar.IRepository.Recharge;
using Znyc.CloudCar.IServices.Auth;
using Znyc.CloudCar.IServices.Currency;
using Znyc.CloudCar.IServices.User;
using Znyc.CloudCar.Model.Dtos.Auth;
using Znyc.CloudCar.Model.Entities;
using Znyc.CloudCar.Model.ViewModels.ReportsCallBack;
using Znyc.CloudCar.Utility.Attributes;
using Znyc.CloudCar.Utility.Extensions;
using Znyc.CloudCar.Utility.Helper;
namespace Znyc.CloudCar.Services.Auth
{
public class AuthService : IAuthService
{
private readonly IRedisOperationRepository _redisCache;
private readonly IHttpContextUser _httpContextUser;
private readonly IRechargeIntroRepository _rechargeIntroRepository;
private readonly IOrderRepository _orderRepository;
private readonly IOrderDetailRepository _orderDetailRepository;
private readonly IPaymentRecordRepository _paymentRecordRepository;
private readonly ILogger<AuthService> _logger;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly ICurrencyService _currencyService;
private readonly IUserCardService _userCardService;
private readonly ICardIntroRepository _cardIntroRepository;
//private readonly IRedisOperationRepository _redisOperationRepository;
//private readonly IWeChatApiHttpClientFactory _weChatApiHttpClientFactory;
private readonly WeChatOptions _weChatOptions;
private readonly TenpayOptions _tenpayOptions;
private readonly IWechatTenpayHttpClientFactory _tenpayHttpClientFactory;
public AuthService(
IRedisOperationRepository redisCache,
IHttpContextUser httpContextUser,
IRechargeIntroRepository rechargeIntroRepository,
IOrderRepository orderRepository,
IOrderDetailRepository orderDetailRepository,
IPaymentRecordRepository paymentRecordRepository,
ILogger<AuthService> logger,
IHttpContextAccessor httpContextAccessor,
ICurrencyService currencyService,
IUserCardService userCardService,
ICardIntroRepository cardIntroRepository,
//IRedisOperationRepository redisOperationRepository,
//IWeChatApiHttpClientFactory weChatApiHttpClientFactory,
IOptions<WeChatOptions> weChatOptions,
IOptions<TenpayOptions> tenpayOptions,
IWechatTenpayHttpClientFactory tenpayHttpClientFactory
)
{
_redisCache = redisCache;
_httpContextUser = httpContextUser;
_rechargeIntroRepository = rechargeIntroRepository;
_orderRepository = orderRepository;
_orderDetailRepository = orderDetailRepository;
_paymentRecordRepository = paymentRecordRepository;
_logger = logger;
_httpContextAccessor = httpContextAccessor;
_currencyService = currencyService;
_userCardService = userCardService;
_cardIntroRepository = cardIntroRepository;
// _redisOperationRepository = redisOperationRepository;
//_weChatApiHttpClientFactory = weChatApiHttpClientFactory;
_weChatOptions = weChatOptions.Value;
_tenpayOptions = tenpayOptions.Value;
_tenpayHttpClientFactory = tenpayHttpClientFactory;
}
/// <summary>
/// 获取百度AccessToken
/// </summary>
/// <returns></returns>
public ResponseOutput GetAccessTokenAsync()
{
string key = string.Format(GlobalCacheKeyVars.BaiduAccessToken, AppSettingsConstVars.ApiKey);
BaiduAccessTokenOutput baiduAccessToken = _redisCache.Get<BaiduAccessTokenOutput>(key);
if (baiduAccessToken.IsNull())
{
string authHost =
$"https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id={ AppSettingsConstVars.ApiKey }&client_secret={ AppSettingsConstVars.SecretKey }&";
HttpClient client = new HttpClient();
HttpResponseMessage response = client.GetAsync(authHost).Result;
baiduAccessToken =
JsonConvert.DeserializeObject<BaiduAccessTokenOutput>(response.Content.ReadAsStringAsync().Result);
_redisCache.SetAsync(key, baiduAccessToken, TimeSpan.FromDays(30));
}
ResponseOutput output = new ResponseOutput()
{
Data = baiduAccessToken,
Successed = true,
Code = 1
};
return output;
}
/// <summary>
/// 微信支付
/// </summary>
/// <param name="productId"></param>
/// <param name="type"></param>
/// <returns></returns>
[Transaction]
public async Task<ResponseOutput> WxPay(long productId, int type)
{
if (type == (int)GlobalEnumVars.OrderType.BuyCurrency)
{
RechargeIntroEntity entity = await _rechargeIntroRepository.GetAsync(productId);
if (entity.IsNotNull())
{
//订单信息
OrderEntity order = await _orderRepository.InsertAsync(new OrderEntity
{
OrderSn = CommonHelper.GetOrderSn(productId),
UserId = _httpContextUser.Id,
PaymentMethod = (int)GlobalEnumVars.PaymentMethod.WX,
OrderMoney = entity.Price,
DistrictMoney = 0,
PaymentMoney = entity.Price,
ShippingCompName = "",
ShippingSn = "",
PayTime = DateTime.Now,
OrderStatus = (int)GlobalEnumVars.OrderStatus.NotPaying,
OrderCurrency = entity.ProductValue,
OrderType = type
});
//明细
await _orderDetailRepository.InsertAsync(new OrderDetailEntity
{
OrderId = order.Id,
ProductId = productId,
ProductName = entity.ProductName,
ProductPrice = entity.Price
});
//付款记录
PaymentRecordEntity paymentRecord = await _paymentRecordRepository.InsertAsync(new PaymentRecordEntity
{
UserId = _httpContextUser.Id,
OrderId = order.Id,
PaySn = "",
PayStatus = (int)GlobalEnumVars.OrderStatus.NotPaying,
PayPlatform = (int)GlobalEnumVars.PaymentMethod.WX,
PaymentMoney = order.PaymentMoney
});
return await CreateOrderByJsapi(_httpContextUser.OpenId, entity.ProductName, order.PaymentMoney.ObjectToInt(),
paymentRecord.Id);
}
return new ResponseOutput()
{
Successed = false,
Msg = "商品信息不存在",
Code = 0
};
}
else
{
CardIntroEntity entity = await _cardIntroRepository.GetAsync(x => x.Id == productId);
if (entity.IsNotNull())
{
//订单信息
OrderEntity order = await _orderRepository.InsertAsync(new OrderEntity
{
OrderSn = CommonHelper.GetOrderSn(productId),
UserId = _httpContextUser.Id,
PaymentMethod = (int)GlobalEnumVars.PaymentMethod.WX,
OrderMoney = entity.CardValue,
DistrictMoney = 0,
PaymentMoney = entity.CardValue,
ShippingCompName = "",
ShippingSn = "",
PayTime = DateTime.Now,
OrderStatus = (int)GlobalEnumVars.OrderStatus.NotPaying,
OrderCurrency = entity.SendValue,
OrderType = type
});
//明细
await _orderDetailRepository.InsertAsync(new OrderDetailEntity
{
OrderId = order.Id,
ProductId = productId,
ProductName = entity.CardName,
ProductPrice = entity.CardValue
});
//付款记录
PaymentRecordEntity paymentRecord = await _paymentRecordRepository.InsertAsync(new PaymentRecordEntity
{
UserId = _httpContextUser.Id,
OrderId = order.Id,
PaySn = "",
PayStatus = (int)GlobalEnumVars.OrderStatus.NotPaying,
PayPlatform = (int)GlobalEnumVars.PaymentMethod.WX,
PaymentMoney = order.PaymentMoney
});
return await CreateOrderByJsapi(_httpContextUser.OpenId, entity.CardName, order.PaymentMoney.ObjectToInt(),
paymentRecord.Id);
}
return new ResponseOutput()
{
Successed = false,
Msg = "商品信息不存在",
Code = 0
};
}
}
/// <summary>
/// 微信小程序支付回调
/// </summary>
/// <returns></returns>
[Transaction]
public async Task<string> NotifyUrl(string content)
{
try
{
_logger.LogError("NotifyUrl");
var client = _tenpayHttpClientFactory.Create(_tenpayOptions.Merchants[0].MerchantId);
var callbackModel = client.DeserializeEvent(content);
if ("TRANSACTION.SUCCESS".Equals(callbackModel.EventType))
{
var callbackResource = client.DecryptEventResource<TransactionResource>(callbackModel);
//attach
string paymentId = callbackResource.Attachment;
//业务处理
PaymentRecordEntity paymentRecord = await _paymentRecordRepository.GetAsync(Convert.ToInt64(paymentId));
if (paymentRecord.IsNotNull())
{
paymentRecord.PayStatus = (int)GlobalEnumVars.PayStatus.Paying;
await _paymentRecordRepository.UpdateAsync(paymentRecord);
//order
OrderEntity order = await _orderRepository.GetAsync(paymentRecord.OrderId);
if (order.IsNotNull())
{
//积分操作
var orderDetail = await _orderDetailRepository.Select.Where(x => x.OrderId == order.Id)
.ToOneAsync();
if (order.OrderStatus != (int)GlobalEnumVars.OrderStatus.Paying)
{
if (order.OrderType == (int)GlobalEnumVars.OrderType.BuyCurrency)
{
RechargeIntroEntity entity = await _rechargeIntroRepository.GetAsync(orderDetail.ProductId);
await _currencyService.AddCurrencyByCharge(order.UserId, order.Id, entity.AllValue);
}
if (order.OrderType == (int)GlobalEnumVars.OrderType.PreferentialCard)
{
CardIntroEntity entity = await _cardIntroRepository.GetAsync(x => x.Id == orderDetail.ProductId);
await _currencyService.AddCurrencyByBuyCard(order.UserId, order.Id, entity.SendValue);
await _userCardService.AddUserCardAsync(order.UserId, entity.Id, entity.Aging);
}
}
order.OrderStatus = (int)GlobalEnumVars.OrderStatus.Paying;
await _orderRepository.UpdateAsync(order);
}
}
}
string xml = "<xml>"
+ "<return_code>SUCCESS</return_code>"
+ "<return_msg>OK</return_msg>"
+ "</xml>";
return xml;
}
catch (Exception ex)
{
_logger.LogError(ex, ex.Message);
string xml = "<xml>"
+ "<return_code>FAIL</return_code>"
+ "<return_msg>支付通知失败</return_msg>"
+ "</xml>";
return xml;
}
}
/// <summary>
/// 获取微信access_token
/// </summary>
/// <returns></returns>
public WxAccessTokenOutput GetWxAccessTokenAsync()
{
//var client = _weChatApiHttpClientFactory.CreateWxOpenClient();
//var request = new CgibinTokenRequest();
//var response = await client.ExecuteCgibinTokenAsync(request);
//await _redisOperationRepository.SetAsync(
// GlobalEnumVars.AccessTokenEnum.WxOpenAccessToken.ToString(), response.AccessToken, TimeSpan.FromDays(30));
//var accessToken = await _redisOperationRepository.GetAsync(GlobalEnumVars.AccessTokenEnum.WxOpenAccessToken.ToString());
//return accessToken;
string key = string.Format(GlobalCacheKeyVars.WxAccessToken, _weChatOptions.WxOpenAppId);
WxAccessTokenOutput wxAccessToken = _redisCache.Get<WxAccessTokenOutput>(key);
if (wxAccessToken.IsNull())
{
string authHost =
$"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={_weChatOptions.WxOpenAppId}&secret={_weChatOptions.WxOpenAppSecret}";
HttpClient client = new HttpClient();
HttpResponseMessage response = client.GetAsync(authHost).Result;
wxAccessToken =
JsonConvert.DeserializeObject<WxAccessTokenOutput>(response.Content.ReadAsStringAsync().Result);
_redisCache.SetAsync(key, wxAccessToken, TimeSpan.FromHours(1.5));
}
return wxAccessToken;
}
/// <summary>
/// 获取小程序
/// </summary>
/// <returns></returns>
public ResponseOutput GetUnlimitedAsync()
{
//var accessToken = WeChatCacheAccessTokenHelper.GetWxOpenAccessToken();
string key = string.Format(GlobalCacheKeyVars.WxAccessToken, _weChatOptions.WxOpenAppId);
WxAccessTokenOutput wxAccessToken = _redisCache.Get<WxAccessTokenOutput>(key);
if (wxAccessToken.IsNull())
{
wxAccessToken = GetWxAccessTokenAsync();
}
string authHost =
$"https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token={wxAccessToken.access_token}";
System.Net.HttpWebRequest request;
request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(authHost);
request.Method = "POST";
request.ContentType = "application/json;charset=UTF-8";
string scene = $"Id={_httpContextUser.Id}";
string options = "{\"scene\":\"" + scene + "\",\"page\":\"pages/index/index\"}";
byte[] payload = Encoding.UTF8.GetBytes(options);
request.ContentLength = payload.Length;
Stream writer = request.GetRequestStream();
writer.Write(payload, 0, payload.Length);
writer.Close();
System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)request.GetResponse();
Stream s = response.GetResponseStream();
List<byte> bytes = new List<byte>();
int temp = s.ReadByte();
while (temp != -1)
{
bytes.Add((byte)temp);
temp = s.ReadByte();
}
byte[] result = bytes.ToArray();
string base64 = Convert.ToBase64String(result);//将byte[]转为base64
return new ResponseOutput()
{
Data = "{\"errcode\":0,\"errmsg\":\"获取成功\",\"buffer\":\"" + base64 + "\"}",
Successed = true,
Code = 1
};
}
/// <summary>
/// 获取小程序
/// </summary>
/// <returns></returns>
public ResponseOutput GetQrCodeAsync(long id)
{
//var accessToken = WeChatCacheAccessTokenHelper.GetWxOpenAccessToken();
string key = string.Format(GlobalCacheKeyVars.WxAccessToken, _weChatOptions.WxOpenAppId);
WxAccessTokenOutput wxAccessToken = _redisCache.Get<WxAccessTokenOutput>(key);
if (wxAccessToken.IsNull())
{
wxAccessToken = GetWxAccessTokenAsync();
}
string authHost =
$"https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token={wxAccessToken.access_token}";
System.Net.HttpWebRequest request;
request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(authHost);
request.Method = "POST";
request.ContentType = "application/json;charset=UTF-8";
string scene = $"{id},{_httpContextUser.Id}";
string options = "{\"scene\":\"" + scene + "\",\"page\":\"pages/detail/detail\"}";
byte[] payload = Encoding.UTF8.GetBytes(options);
request.ContentLength = payload.Length;
Stream writer = request.GetRequestStream();
writer.Write(payload, 0, payload.Length);
writer.Close();
System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)request.GetResponse();
Stream s = response.GetResponseStream();
List<byte> bytes = new List<byte>();
int temp = s.ReadByte();
while (temp != -1)
{
bytes.Add((byte)temp);
temp = s.ReadByte();
}
byte[] result = bytes.ToArray();
string base64 = Convert.ToBase64String(result);//将byte[]转为base64
return new ResponseOutput()
{
Data = "{\"errcode\":0,\"errmsg\":\"获取成功\",\"buffer\":\"" + base64 + "\"}",
Successed = true,
Code = 1
};
}
/// <summary>
/// JSAPI下单支付
/// </summary>
/// <param name="openId"></param>
/// <param name="body"></param>
/// <param name="price"></param>
/// <param name="paymentId"></param>
/// <returns></returns>
public async Task<ResponseOutput> CreateOrderByJsapi(string openId, string body, int price, long paymentId)
{
var manager = new InMemoryCertificateManager();
var options = new WechatTenpayClientOptions()
{
MerchantId = _tenpayOptions.Merchants[0].MerchantId,
MerchantV3Secret = _tenpayOptions.Merchants[0].SecretV3,
MerchantCertificateSerialNumber = _tenpayOptions.Merchants[0].CertSerialNumber,
MerchantCertificatePrivateKey = @"-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDF+wWe6XTe/o1K
8Ri2lXMRJFgtjZYjxX9E8GZt7rirZRMlsgpqBjymJt/7P2LAxqafUbM9bMOlo6Ec
ppjyw8yrSGTaHqSzWhoP7NuxpCw9Y4x8QOCIjsp0+UV6aE/AVw/+jfhkn7dBfAqP
kIrpRlLjTYti0GSLwPVYCHDHKyYKo2pXbAlCpLjZY0c5Q4cAajPYLUrtAd9Jwzo1
vt8aTcIsgPVK8nXJM00BYsvT9NVlV15eWgU/cXg1tzJN6ZT6t75c4iTu9aoGTp2b
x0Zd6OsK0FZ4NwfvcQIKHxzShbjeTuK3SMkNd3asvUXsUpus6dJbryEg2d3Emura
SaVcg5tLAgMBAAECggEASOTt4t7OOzS6TTeMA93u6gbZuJwDBdS30Wg6LovQzrp+
XEi7cOIu/nYdzeI+t//sZYitWBZtytT+gxAMDIZvGzmieHUD601nfymUkkmCSHAY
z78LbPw2Ku+E11cE1iq4Jt+a72GnFaNYOBfeLZnI9wwcIBveiV5YdztUWuDWNt/i
JO8+cQol/y9gZqZeZSkE+ksM6SvQzhfEuGzQDXjYyOiIgja+M2mMLw2GQnqryDky
giBmJkqpCFXMw9GQa8lnM5Tw7WRsGoJm/NzMsUuyIT3kwSeUOPlkLd0mzJTcDmmR
HRKV6D5lQEH+sxYrCdJ+AgBLOKdg9GALfjdSK/c8IQKBgQDw0kBMDdUwgvJ6JOT1
uxlnsXz1BLh1NcS9LzM04h+Bt80omAzwt8jeXW9OgqwvOenWoi58Du4I8RsxnoFC
tktqaBqW3a8e47b4UJ1LHr15OukxM24Kkulg7+2/MexMTmN2AYVskqI5Y8ebcQnt
WrYkar2VeedEANFZx5GF4NlMSQKBgQDSdYSmmw5Oi7oHuhkhOKz3/uH+vWWM2yTX
tgFml+iWy8+k8uYxw1BAwoeqNzJNqH/7goKSIudhZt5G/Fz3i1ZAFdYVix5XCLjF
3ySz6NPyLGo2MJpWSCoLPqHGFp6jFHmXzDySUsT4YcWeCT88yBM3lGgqJL7Eq8dc
gysJqCqi8wKBgQDhL5lUBLNPM4NNV+aJKTUuUzdHXeymHWskhFhboP5ZK+e5h8TB
6vj3hWMphONBHeRdATZ6ZvOKhPoqwc6Y9SE8FLCYVh8EwWY8eBU9QzdlfwLDMRY6
6Pk13eTwndwZ1ksG85Ex30O2amkiHudrfSFImE9C0MTCQAmC7CxVhdVrkQKBgAbx
XYjpgJVSwrZSi1WvOvWLcQUoVltJN3PuSymJRWEEJDt6z+FAYjtgr30MCRrKvj4b
1hbgE+YAsMCCvsZj0FqY3dEkH8IbRY0xiVJuEd/hWzeibtT92HU6gbe5M06J9GDv
mefx1xGimBRYlb95kji5Kp6JS8nNKOyCXz8YTx/FAoGBAKKMZgPpN+4Qd1ZuvALm
couRMQf6EWuCB7u9VuzJW/aaAIEGEXCC4HLEIYpROBwNrG313yseGVzPT2txoxw6
u2XjfkdEkhLU3W54TSw4EJedWE5d+TGGqf9eMRdUbhCXylPzTlxmnFwGb0Z31eh7
MndPWjaUAjvKQ5xFYg4gUezL
-----END PRIVATE KEY-----",
PlatformCertificateManager = manager // 证书管理器的具体用法请参阅下文的高级技巧与加密、验签有关的章节
};
var client = new WechatTenpayClient(options);
//var client = _tenpayHttpClientFactory.Create(_tenpayOptions.Merchants[0].MerchantId);
var request = new CreatePayTransactionJsapiRequest()
{
OutTradeNumber = $"{_tenpayOptions.Merchants[0].MerchantId}" + DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff"),
AppId = _weChatOptions.WxOpenAppId,
Description = body,
ExpireTime = DateTimeOffset.Now.AddMinutes(15),
NotifyUrl = _tenpayOptions.NotifyUrl,
Amount = new CreatePayTransactionJsapiRequest.Types.Amount() { Total = price * 100 },
Payer = new CreatePayTransactionJsapiRequest.Types.Payer() { OpenId = openId },
Attachment = paymentId.ToString()
};
var response = await client.ExecuteCreatePayTransactionJsapiAsync(request);
if (!response.IsSuccessful())
{
_logger.LogWarning(
"JSAPI 下单失败(状态码:{0},错误代码:{1},错误描述:{2})。",
response.RawStatus, response.ErrorCode, response.ErrorMessage
);
}
var paramMap = client.GenerateParametersForJsapiPayRequest(request.AppId, response.PrepayId);
return new ResponseOutput() { Data = paramMap, Successed = true, Code = 1 };
}
}
}