feat: 新增微信小程序模块
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
namespace Yi.Framework.WeChat.MiniProgram.Abstract;
|
||||
|
||||
public interface IErrorObjct: IHasErrcode, IHasErrmsg
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Yi.Framework.WeChat.MiniProgram.Abstract;
|
||||
|
||||
public interface IHasErrcode
|
||||
{
|
||||
public int errcode { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Yi.Framework.WeChat.MiniProgram.Abstract;
|
||||
|
||||
public interface IHasErrmsg
|
||||
{
|
||||
string errmsg { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace Yi.Framework.WeChat.MiniProgram.HttpModels;
|
||||
|
||||
public class AccessTokenResponse
|
||||
{
|
||||
public string access_token { get; set; }
|
||||
|
||||
public int expires_in { get; set; }
|
||||
}
|
||||
|
||||
public class AccessTokenRequest
|
||||
{
|
||||
public string grant_type { get; set; }
|
||||
public string appid { get; set; }
|
||||
public string secret { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using Yi.Framework.WeChat.MiniProgram.Abstract;
|
||||
|
||||
namespace Yi.Framework.WeChat.MiniProgram.HttpModels;
|
||||
|
||||
|
||||
public class Code2SessionResponse: IErrorObjct
|
||||
{
|
||||
public string openid { get; set; }
|
||||
public string session_key { get; set; }
|
||||
public string unionid { get; set; }
|
||||
public int errcode { get; set; }
|
||||
public string errmsg { get; set; }
|
||||
}
|
||||
|
||||
public class Code2SessionRequest
|
||||
{
|
||||
public string appid { get; set; }
|
||||
public string secret { get; set; }
|
||||
public string js_code { get; set; }
|
||||
public string grant_type => "authorization_code";
|
||||
}
|
||||
|
||||
public class Code2SessionInput
|
||||
{
|
||||
public Code2SessionInput(string js_code)
|
||||
{
|
||||
|
||||
this.js_code=js_code;
|
||||
}
|
||||
public string js_code { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using Yi.Framework.WeChat.MiniProgram.HttpModels;
|
||||
|
||||
namespace Yi.Framework.WeChat.MiniProgram;
|
||||
|
||||
public interface IWeChatMiniProgramManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取用户openid
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task<Code2SessionResponse> Code2SessionAsync(Code2SessionInput input);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using Microsoft.Extensions.Caching.Distributed;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Volo.Abp.Caching;
|
||||
|
||||
namespace Yi.Framework.WeChat.MiniProgram.Token;
|
||||
|
||||
internal class CacheMiniProgramToken : DefaultMinProgramToken, IMiniProgramToken
|
||||
{
|
||||
private IDistributedCache<string> _cache;
|
||||
private const string CacheKey = "MiniProgramToken";
|
||||
|
||||
public CacheMiniProgramToken(IOptions<WeChatMiniProgramOptions> options, IDistributedCache<string> cache) :
|
||||
base(options)
|
||||
{
|
||||
_cache = cache;
|
||||
}
|
||||
|
||||
public async Task<string> GetTokenAsync()
|
||||
{
|
||||
return await _cache.GetOrAddAsync("MiniProgramToken", async () => { return await base.GetTokenAsync(); }, () =>
|
||||
{
|
||||
return new DistributedCacheEntryOptions()
|
||||
{
|
||||
AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(2) - TimeSpan.FromMinutes(1)
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using System.Net.Http.Json;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Yi.Framework.Core.Extensions;
|
||||
using Yi.Framework.WeChat.MiniProgram.HttpModels;
|
||||
|
||||
namespace Yi.Framework.WeChat.MiniProgram.Token;
|
||||
|
||||
internal class DefaultMinProgramToken:IMiniProgramToken
|
||||
{
|
||||
private const string Url = "https://api.weixin.qq.com/cgi-bin/token";
|
||||
private WeChatMiniProgramOptions _options;
|
||||
public DefaultMinProgramToken(IOptions<WeChatMiniProgramOptions> options)
|
||||
{
|
||||
_options = options.Value;
|
||||
}
|
||||
public async Task<string> GetTokenAsync()
|
||||
{
|
||||
var token = await this.GetAccessToken();
|
||||
return token.access_token;
|
||||
}
|
||||
public async Task<AccessTokenResponse> GetAccessToken()
|
||||
{
|
||||
var req = new AccessTokenRequest();
|
||||
req.appid = _options.AppID;
|
||||
req.secret = _options.AppSecret;
|
||||
req.grant_type = "client_credential";
|
||||
using (HttpClient httpClient = new HttpClient())
|
||||
{
|
||||
string queryString = req.ToQueryString();
|
||||
var builder = new UriBuilder(Url);
|
||||
builder.Query = queryString;
|
||||
HttpResponseMessage response = await httpClient.GetAsync(builder.ToString());
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var responseBody = await response.Content.ReadFromJsonAsync<AccessTokenResponse>();
|
||||
return responseBody;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Yi.Framework.WeChat.MiniProgram.Token;
|
||||
|
||||
public interface IMiniProgramToken
|
||||
{
|
||||
public Task<string> GetTokenAsync();
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
namespace Yi.Framework.WeChat.MiniProgram;
|
||||
|
||||
public class WeChatMiniProgramException: Exception
|
||||
{
|
||||
public override string Message
|
||||
{
|
||||
get
|
||||
{
|
||||
// 加上前缀
|
||||
return "微信Api异常: " + base.Message;
|
||||
}
|
||||
}
|
||||
|
||||
public WeChatMiniProgramException()
|
||||
{
|
||||
}
|
||||
|
||||
public WeChatMiniProgramException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public WeChatMiniProgramException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using System.Reflection;
|
||||
using System.Web;
|
||||
using Yi.Framework.WeChat.MiniProgram.Abstract;
|
||||
|
||||
namespace Yi.Framework.WeChat.MiniProgram;
|
||||
|
||||
public static class WeChatMiniProgramExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 效验请求是否成功
|
||||
/// </summary>
|
||||
/// <param name="response"></param>
|
||||
/// <returns></returns>
|
||||
internal static void ValidateSuccess(this IErrorObjct response)
|
||||
{
|
||||
|
||||
if (response.errcode != 0)
|
||||
{
|
||||
throw new WeChatMiniProgramException(response.errmsg);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string ToQueryString<T>(this T obj)
|
||||
{
|
||||
var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
||||
var queryParams = new List<string>();
|
||||
|
||||
foreach (var prop in properties)
|
||||
{
|
||||
var value = prop.GetValue(obj, null);
|
||||
if (value != null)
|
||||
{
|
||||
// 处理集合
|
||||
if (value is IEnumerable<object> enumerable)
|
||||
{
|
||||
foreach (var item in enumerable)
|
||||
{
|
||||
queryParams.Add($"{HttpUtility.UrlEncode(prop.Name)}={HttpUtility.UrlEncode(item.ToString())}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
queryParams.Add($"{HttpUtility.UrlEncode(prop.Name)}={HttpUtility.UrlEncode(value.ToString())}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return string.Join("&", queryParams);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using System.Net.Http.Json;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Volo.Abp.DependencyInjection;
|
||||
using Yi.Framework.Core.Extensions;
|
||||
using Yi.Framework.WeChat.MiniProgram.HttpModels;
|
||||
using Yi.Framework.WeChat.MiniProgram.Token;
|
||||
|
||||
namespace Yi.Framework.WeChat.MiniProgram;
|
||||
|
||||
public class WeChatMiniProgramManager : IWeChatMiniProgramManager, ISingletonDependency
|
||||
{
|
||||
private IMiniProgramToken _weChatToken;
|
||||
private WeChatMiniProgramOptions _options;
|
||||
|
||||
public WeChatMiniProgramManager(IMiniProgramToken weChatToken, IOptions<WeChatMiniProgramOptions> options)
|
||||
{
|
||||
_weChatToken = weChatToken;
|
||||
_options = options.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户openid
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<Code2SessionResponse> Code2SessionAsync(Code2SessionInput input)
|
||||
{
|
||||
string url = "https://api.weixin.qq.com/sns/jscode2session";
|
||||
var req = new Code2SessionRequest();
|
||||
req.js_code = input.js_code;
|
||||
req.secret = _options.AppSecret;
|
||||
req.appid = _options.AppID;
|
||||
|
||||
using (HttpClient httpClient = new HttpClient())
|
||||
{
|
||||
string queryString = req.ToQueryString();
|
||||
var builder = new UriBuilder(url);
|
||||
builder.Query = queryString;
|
||||
HttpResponseMessage response = await httpClient.GetAsync(builder.ToString());
|
||||
var responseBody = await response.Content.ReadFromJsonAsync<Code2SessionResponse>();
|
||||
|
||||
responseBody.ValidateSuccess();
|
||||
|
||||
return responseBody;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace Yi.Framework.WeChat.MiniProgram;
|
||||
|
||||
public class WeChatMiniProgramOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// AppId
|
||||
/// </summary>
|
||||
public string AppID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// App密钥
|
||||
/// </summary>
|
||||
public string AppSecret { get; set; }
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user