mirror of
http://git.coreshop.cn/jianweie/coreshoppro.git
synced 2025-12-06 19:23:25 +08:00
【新增】实现支付宝小程序适配。
This commit is contained in:
@@ -0,0 +1,193 @@
|
||||
using CoreCms.Net.Auth.Policys;
|
||||
using CoreCms.Net.Caching.AutoMate.RedisCache;
|
||||
using CoreCms.Net.IServices;
|
||||
using CoreCms.Net.Model.ViewModels.UI;
|
||||
using CoreCms.Net.Utility.Extensions;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using CoreCms.Net.Model.Entities;
|
||||
using CoreCms.Net.Model.FromBody;
|
||||
using CoreCms.Net.Configuration;
|
||||
using static SKIT.FlurlHttpClient.Wechat.Api.Models.WeDataQueryBindListResponse.Types;
|
||||
|
||||
namespace CoreCms.Net.Web.WebApi.Controllers.AliPayOAuth
|
||||
{
|
||||
/// <summary>
|
||||
/// 支付宝业务交互接口
|
||||
/// </summary>
|
||||
[Route("api/[controller]/[action]")]
|
||||
[ApiController]
|
||||
public class AliPayAuthController : ControllerBase
|
||||
{
|
||||
private readonly IAliPayServices _aliPayService;
|
||||
private readonly PermissionRequirement _permissionRequirement;
|
||||
private readonly ICoreCmsAliPayUserInfoServices _aliPayUserServices;
|
||||
private readonly IRedisOperationRepository _redisOperationRepository;
|
||||
private readonly ICoreCmsUserServices _userServices;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly ICoreCmsUserLogServices _userLogServices;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public AliPayAuthController(PermissionRequirement permissionRequirement, IRedisOperationRepository redisOperationRepository, ICoreCmsAliPayUserInfoServices aliPayUserServices, IAliPayServices aliPayService, ICoreCmsUserServices userServices, IHttpContextAccessor httpContextAccessor, ICoreCmsUserLogServices userLogServices)
|
||||
{
|
||||
_permissionRequirement = permissionRequirement;
|
||||
_redisOperationRepository = redisOperationRepository;
|
||||
_aliPayUserServices = aliPayUserServices;
|
||||
_aliPayService = aliPayService;
|
||||
_userServices = userServices;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_userLogServices = userLogServices;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 静默通过code票据返回app_auth_token相关信息
|
||||
/// 前端是getAuthCode方法
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<WebApiCallBack> GetAliPayAppAuthTokenByCode([FromBody] FMStringId entity)
|
||||
{
|
||||
var jm = new WebApiCallBack();
|
||||
|
||||
var lockKey = "LOCK_OnLogin:user_" + entity.id;
|
||||
var lockHolder = Guid.NewGuid().ToString("N"); //锁持有者
|
||||
var redisUserLock = await _redisOperationRepository.LockTakeAsync(lockKey, lockHolder, TimeSpan.FromSeconds(10));
|
||||
|
||||
if (redisUserLock)
|
||||
{
|
||||
if (string.IsNullOrEmpty(entity.id))
|
||||
{
|
||||
jm.msg = "请提交code";
|
||||
return jm;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var result = _aliPayService.GetAliPayAppAuthTokenBYCode(entity.id);
|
||||
|
||||
if (!result.IsError)
|
||||
{
|
||||
var userInfo = await _aliPayUserServices.QueryByClauseAsync(p => p.userId == result.UserId);
|
||||
if (userInfo != null)
|
||||
{
|
||||
userInfo.reExpiresIn = result.ReExpiresIn.ObjectToInt();
|
||||
userInfo.expiresIn = result.ExpiresIn.ObjectToInt();
|
||||
userInfo.refreshToken = result.RefreshToken;
|
||||
userInfo.accessToken = result.AccessToken;
|
||||
|
||||
await _aliPayUserServices.UpdateAsync(userInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
userInfo = new CoreCmsAliPayUserInfo();
|
||||
//事物处理过程开始
|
||||
userInfo.accessToken = result.AccessToken;
|
||||
userInfo.aliPayUserInfoId = result.AlipayUserId;
|
||||
userInfo.authStart = result.AuthStart;
|
||||
userInfo.expiresIn = result.ExpiresIn.ObjectToInt();
|
||||
userInfo.reExpiresIn = result.ReExpiresIn.ObjectToInt();
|
||||
userInfo.refreshToken = result.RefreshToken;
|
||||
userInfo.userId = result.UserId;
|
||||
userInfo.openId = result.OpenId;
|
||||
userInfo.unionId = result.UnionId;
|
||||
userInfo.createTime = DateTime.Now;
|
||||
userInfo.userInfoId = 0;
|
||||
|
||||
var resultData = await _aliPayUserServices.InsertAsync(userInfo, true);
|
||||
|
||||
userInfo.id = resultData;
|
||||
}
|
||||
|
||||
|
||||
if (userInfo is { userInfoId: > 0 })
|
||||
{
|
||||
var user = await _userServices.QueryByClauseAsync(p => p.id == userInfo.userInfoId);
|
||||
if (user != null)
|
||||
{
|
||||
if (user.status == (int)GlobalEnumVars.UserStatus.停用)
|
||||
{
|
||||
jm.status = false;
|
||||
jm.msg = "您的账号已经被禁用。";
|
||||
return jm;
|
||||
}
|
||||
|
||||
if (user.isDelete)
|
||||
{
|
||||
jm.status = false;
|
||||
jm.msg = "您的账号已经被禁用。";
|
||||
return jm;
|
||||
}
|
||||
|
||||
var claims = new List<Claim> {
|
||||
new Claim(ClaimTypes.Name, user.nickName),
|
||||
new Claim(JwtRegisteredClaimNames.Jti, user.id.ToString()),
|
||||
new Claim(ClaimTypes.Expiration, DateTime.Now.AddSeconds(_permissionRequirement.Expiration.TotalSeconds).ToString(CultureInfo.InvariantCulture)) };
|
||||
|
||||
//用户标识
|
||||
var identity = new ClaimsIdentity(JwtBearerDefaults.AuthenticationScheme);
|
||||
identity.AddClaims(claims);
|
||||
jm.status = true;
|
||||
jm.data = new
|
||||
{
|
||||
auth = JwtToken.BuildJwtToken(claims.ToArray(), _permissionRequirement),
|
||||
user
|
||||
};
|
||||
jm.otherData = result.UserId;
|
||||
|
||||
//录入登录日志
|
||||
var log = new CoreCmsUserLog
|
||||
{
|
||||
userId = user.id,
|
||||
state = (int)GlobalEnumVars.UserLogTypes.登录,
|
||||
ip = _httpContextAccessor.HttpContext?.Connection.RemoteIpAddress != null ? _httpContextAccessor.HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString() : "127.0.0.1",
|
||||
createTime = DateTime.Now,
|
||||
parameters = GlobalEnumVars.UserLogTypes.登录.ToString()
|
||||
};
|
||||
await _userLogServices.InsertAsync(log);
|
||||
|
||||
return jm;
|
||||
}
|
||||
}
|
||||
jm.status = true;
|
||||
jm.data = result.UserId;
|
||||
jm.otherData = result.UserId;
|
||||
}
|
||||
else
|
||||
{
|
||||
jm.status = false;
|
||||
jm.msg = result.SubMsg;
|
||||
jm.data = result;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
jm.status = false;
|
||||
jm.msg = e.Message;
|
||||
jm.data = e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
await _redisOperationRepository.LockReleaseAsync(lockKey, lockHolder);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
jm.msg = "当前请求太频繁_请稍后再试";
|
||||
}
|
||||
return jm;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,11 @@ using System.Globalization;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Aop.Api;
|
||||
using Aop.Api.Util;
|
||||
using CoreCms.Net.Auth.HttpContextUser;
|
||||
using CoreCms.Net.Auth.Policys;
|
||||
using CoreCms.Net.Caching.AccressToken;
|
||||
@@ -27,6 +30,8 @@ using CoreCms.Net.Loging;
|
||||
using CoreCms.Net.Model.Entities;
|
||||
using CoreCms.Net.Model.Entities.Expression;
|
||||
using CoreCms.Net.Model.FromBody;
|
||||
using CoreCms.Net.Model.Options;
|
||||
using CoreCms.Net.Model.ViewModels.AliPay;
|
||||
using CoreCms.Net.Model.ViewModels.DTO;
|
||||
using CoreCms.Net.Model.ViewModels.UI;
|
||||
using CoreCms.Net.Utility.Extensions;
|
||||
@@ -92,6 +97,8 @@ namespace CoreCms.Net.Web.WebApi.Controllers
|
||||
private readonly IWeChatApiHttpClientFactory _weChatApiHttpClientFactory;
|
||||
private readonly WeChatOptions _weChatOptions;
|
||||
private readonly IRedisOperationRepository _redisOperationRepository;
|
||||
private readonly ICoreCmsAliPayUserInfoServices _aliPayUserInfoServices;
|
||||
private readonly AliPayOptions _aliPayOptions;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
@@ -122,7 +129,7 @@ namespace CoreCms.Net.Web.WebApi.Controllers
|
||||
, ICoreCmsSettingServices settingServices
|
||||
, ICoreCmsServicesServices servicesServices
|
||||
, IOptions<WeChatOptions> weChatOptions
|
||||
, ICoreCmsUserServicesOrderServices userServicesOrderServices, ICoreCmsUserServicesTicketServices userServicesTicketServices, ICoreCmsStoreServices storeServices, ICoreCmsCouponServices couponServices, ICoreCmsOrderServices orderServices, IWeChatApiHttpClientFactory weChatApiHttpClientFactory, IRedisOperationRepository redisOperationRepository)
|
||||
, ICoreCmsUserServicesOrderServices userServicesOrderServices, ICoreCmsUserServicesTicketServices userServicesTicketServices, ICoreCmsStoreServices storeServices, ICoreCmsCouponServices couponServices, ICoreCmsOrderServices orderServices, IWeChatApiHttpClientFactory weChatApiHttpClientFactory, IRedisOperationRepository redisOperationRepository, ICoreCmsAliPayUserInfoServices aliPayUserInfoServices, IOptions<AliPayOptions> aliPayOptions)
|
||||
{
|
||||
_user = user;
|
||||
_userWeChatInfoServices = userWeChatInfoServices;
|
||||
@@ -155,6 +162,8 @@ namespace CoreCms.Net.Web.WebApi.Controllers
|
||||
_orderServices = orderServices;
|
||||
_weChatApiHttpClientFactory = weChatApiHttpClientFactory;
|
||||
_redisOperationRepository = redisOperationRepository;
|
||||
_aliPayUserInfoServices = aliPayUserInfoServices;
|
||||
_aliPayOptions = aliPayOptions.Value;
|
||||
_weChatOptions = weChatOptions.Value;
|
||||
|
||||
}
|
||||
@@ -533,7 +542,7 @@ namespace CoreCms.Net.Web.WebApi.Controllers
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<WebApiCallBack> SmsLogin([FromBody] FMWxAccountCreate entity)
|
||||
public async Task<WebApiCallBack> SmsLogin([FromBody] FMComAccountCreate entity)
|
||||
{
|
||||
var jm = await _userServices.SmsLogin(entity, (int)GlobalEnumVars.LoginType.Sms, entity.platform);
|
||||
return jm;
|
||||
@@ -573,7 +582,7 @@ namespace CoreCms.Net.Web.WebApi.Controllers
|
||||
return jm;
|
||||
}
|
||||
|
||||
var data = new FMWxAccountCreate
|
||||
var data = new FMComAccountCreate
|
||||
{
|
||||
mobile = phoneNumber.phoneNumber,
|
||||
invitecode = entity.invitecode,
|
||||
@@ -587,6 +596,124 @@ namespace CoreCms.Net.Web.WebApi.Controllers
|
||||
|
||||
#endregion
|
||||
|
||||
#region 支付宝小程序授权拉取手机号码
|
||||
|
||||
/// <summary>
|
||||
/// 支付宝小程序授权拉取手机号码
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<WebApiCallBack> DecryptPhoneNumberByAli([FromBody] FMAliLoginDecryptPhoneNumber entity)
|
||||
{
|
||||
var jm = new WebApiCallBack();
|
||||
|
||||
var userInfo = await _aliPayUserInfoServices.QueryByClauseAsync(p => p.userId == entity.sessionAuthId || p.openId == entity.sessionAuthId);
|
||||
if (userInfo == null)
|
||||
{
|
||||
jm.status = false;
|
||||
jm.msg = "支付宝用户信息获取失败";
|
||||
return jm;
|
||||
}
|
||||
|
||||
//1. 获取验签和解密所需要的参数
|
||||
var content = entity.encryptedData;
|
||||
// 是否为加密报文
|
||||
var isDataEncrypted = !content.StartsWith("{", StringComparison.Ordinal);
|
||||
var signCheckPass = false;
|
||||
//2. 验签
|
||||
var signContent = content;
|
||||
var decryptKey = _aliPayOptions.AESKey;
|
||||
// 如果是加密的报文则需要在密文的前后添加双引号
|
||||
if (isDataEncrypted)
|
||||
{
|
||||
signContent = "\"" + signContent + "\"";
|
||||
}
|
||||
try
|
||||
{
|
||||
signCheckPass = AlipaySignature.RSACheckContent(signContent, entity.sign, _aliPayOptions.AliPublicKey, "UTF-8", "RSA2", false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//验签异常, 日志
|
||||
jm.status = false;
|
||||
jm.msg = "验签失败";
|
||||
jm.code = 500;
|
||||
jm.otherData = ex;
|
||||
NLogUtil.WriteAll(LogLevel.Error, LogType.Web, "小程序接口", "支付宝小程序授权拉取手机号码", ex);
|
||||
return jm;
|
||||
}
|
||||
if (!signCheckPass)
|
||||
{
|
||||
//验签不通过(异常或者报文被篡改),终止流程(不需要做解密)
|
||||
jm.status = false;
|
||||
jm.msg = "验签失败";
|
||||
jm.code = 500;
|
||||
jm.otherData = "验签不通过(异常或者报文被篡改),终止流程(不需要做解密) ";
|
||||
return jm;
|
||||
}
|
||||
//3. 解密
|
||||
string plainData = null;
|
||||
if (isDataEncrypted)
|
||||
{
|
||||
try
|
||||
{
|
||||
plainData = AlipayEncrypt.AesDencrypt(decryptKey, content, "UTF-8");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//解密异常, 记录日志
|
||||
jm.status = false;
|
||||
jm.msg = "解密异常";
|
||||
jm.code = 500;
|
||||
jm.otherData = ex;
|
||||
NLogUtil.WriteAll(LogLevel.Error, LogType.Web, "小程序接口", "支付宝小程序授权拉取手机号码", ex);
|
||||
return jm;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
plainData = content;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(plainData))
|
||||
{
|
||||
var obj = JsonConvert.DeserializeObject<AlipayEncryptDTO>(plainData);
|
||||
if (obj is { code: "10000", msg: "Success" } && !string.IsNullOrEmpty(obj.mobile))
|
||||
{
|
||||
jm.status = true;
|
||||
jm.msg = "获取手机号码成功";
|
||||
jm.data = obj;
|
||||
|
||||
var data = new FMComAccountCreate
|
||||
{
|
||||
mobile = obj.mobile,
|
||||
invitecode = entity.invitecode,
|
||||
sessionAuthId = entity.sessionAuthId
|
||||
};
|
||||
|
||||
jm = await _userServices.SmsLogin(data, (int)GlobalEnumVars.LoginType.AliPhoneNumber);
|
||||
}
|
||||
else
|
||||
{
|
||||
jm.status = false;
|
||||
jm.msg = "数据解码失败";
|
||||
jm.data = obj;
|
||||
jm.otherData = plainData;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
jm.status = false;
|
||||
jm.msg = "获取手机号码错误,解密失败。";
|
||||
jm.code = 500;
|
||||
}
|
||||
|
||||
return jm;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 用户短信注册并返回jwt token(弃用)======================================================
|
||||
/// <summary>
|
||||
/// 用户短信注册并返回jwt token(弃用)
|
||||
@@ -595,7 +722,7 @@ namespace CoreCms.Net.Web.WebApi.Controllers
|
||||
/// <returns></returns>
|
||||
[Obsolete]
|
||||
[HttpPost]
|
||||
public async Task<WebApiCallBack> SmsLogin2([FromBody] FMWxAccountCreate entity)
|
||||
public async Task<WebApiCallBack> SmsLogin2([FromBody] FMComAccountCreate entity)
|
||||
{
|
||||
var jm = new WebApiCallBack();
|
||||
if (!CommonHelper.IsMobile(entity.mobile))
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AlipaySDKNet.Standard" Version="4.9.78" />
|
||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="8.0.0" />
|
||||
<PackageReference Include="Autofac.Extras.DynamicProxy" Version="7.1.0" />
|
||||
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1" />
|
||||
|
||||
@@ -103,6 +103,24 @@
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:CoreCms.Net.Web.WebApi.Controllers.AliPayOAuth.AliPayAuthController">
|
||||
<summary>
|
||||
支付宝业务交互接口
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:CoreCms.Net.Web.WebApi.Controllers.AliPayOAuth.AliPayAuthController.#ctor(CoreCms.Net.Auth.Policys.PermissionRequirement,CoreCms.Net.Caching.AutoMate.RedisCache.IRedisOperationRepository,CoreCms.Net.IServices.ICoreCmsAliPayUserInfoServices,CoreCms.Net.IServices.IAliPayServices,CoreCms.Net.IServices.ICoreCmsUserServices,Microsoft.AspNetCore.Http.IHttpContextAccessor,CoreCms.Net.IServices.ICoreCmsUserLogServices)">
|
||||
<summary>
|
||||
构造函数
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:CoreCms.Net.Web.WebApi.Controllers.AliPayOAuth.AliPayAuthController.GetAliPayAppAuthTokenByCode(CoreCms.Net.Model.FromBody.FMStringId)">
|
||||
<summary>
|
||||
静默通过code票据返回app_auth_token相关信息
|
||||
前端是getAuthCode方法
|
||||
</summary>
|
||||
<param name="entity"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:CoreCms.Net.Web.WebApi.Controllers.ArticleController">
|
||||
<summary>
|
||||
文章api控制器
|
||||
|
||||
@@ -72,6 +72,9 @@ builder.Services.AddWeChatPay();
|
||||
//注册自定义微信接口配置文件
|
||||
builder.Services.Configure<CoreCms.Net.WeChat.Service.Options.WeChatOptions>(builder.Configuration.GetSection(nameof(CoreCms.Net.WeChat.Service.Options.WeChatOptions)));
|
||||
|
||||
//注册自定义支付宝接口配置文件
|
||||
builder.Services.Configure<CoreCms.Net.Model.Options.AliPayOptions>(builder.Configuration.GetSection(nameof(CoreCms.Net.Model.Options.AliPayOptions)));
|
||||
|
||||
// 注入工厂 HTTP 客户端
|
||||
builder.Services.AddHttpClient();
|
||||
builder.Services.AddSingleton<CoreCms.Net.WeChat.Service.HttpClients.IWeChatApiHttpClientFactory, CoreCms.Net.WeChat.Service.HttpClients.WeChatApiHttpClientFactory>();
|
||||
|
||||
@@ -103,5 +103,27 @@
|
||||
"WxOpenAppSecret": "",
|
||||
"WxOpenToken": "",
|
||||
"WxOpenEncodingAESKey": ""
|
||||
},
|
||||
"AliPayOptions": {
|
||||
//appid
|
||||
"AppId": "",
|
||||
//应用私钥
|
||||
"AppSecret": "",
|
||||
//支付宝公钥
|
||||
"AliPublicKey": "",
|
||||
//应用公钥
|
||||
"AppPublicKey": "",
|
||||
//回调地址
|
||||
"RedirectUrl": "",
|
||||
//阿里访问令牌刷新
|
||||
"AliAccessTokenRefresh": "",
|
||||
//oauth2授权地址
|
||||
"AppConnectUrl": "https://openauth.alipay.com/oauth2/publicAppAuthorize.htm?",
|
||||
//支付宝授权类型
|
||||
"AppAuthToken": "alipay.open.auth.token.app",
|
||||
//支付宝通用接口
|
||||
"AliPublicApi": "https://openapi.alipay.com/gateway.do",
|
||||
//外部H5唤起支付宝客户端进行实名认证接口地址
|
||||
"AliPayAppAuth": "alipays://platformapi/startapp?appId=20000067&url="
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user