feat: 完成支持微信扫码功能
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Caching.Distributed;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Volo.Abp.Caching;
|
||||
using Volo.Abp.Domain.Services;
|
||||
using Yi.Framework.AiHub.Domain.Entities;
|
||||
using Yi.Framework.AiHub.Domain.Shared.Enums.Fuwuhao;
|
||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||
|
||||
namespace Yi.Framework.AiHub.Domain.Managers.Fuwuhao;
|
||||
|
||||
public class FuwuhaoManager : DomainService
|
||||
{
|
||||
private readonly FuwuhaoOptions _options;
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private IDistributedCache<AccessTokenResponse> _accessTokenCache;
|
||||
private ISqlSugarRepository<AiUserExtraInfoEntity> _userRepository;
|
||||
|
||||
public FuwuhaoManager(IOptions<FuwuhaoOptions> options, IHttpClientFactory httpClientFactory,
|
||||
ISqlSugarRepository<AiUserExtraInfoEntity> userRepository)
|
||||
{
|
||||
_options = options.Value;
|
||||
_httpClientFactory = httpClientFactory;
|
||||
_userRepository = userRepository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取微信公众号AccessToken
|
||||
/// </summary>
|
||||
/// <returns>AccessToken响应对象</returns>
|
||||
private async Task<string> GetAccessTokenAsync()
|
||||
{
|
||||
var output = await _accessTokenCache.GetOrAddAsync("Fuwuhao", async () =>
|
||||
{
|
||||
var url =
|
||||
$"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={_options.AppId}&secret={_options.Secret}";
|
||||
|
||||
var response = await _httpClientFactory.CreateClient().GetAsync(url);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var jsonContent = await response.Content.ReadAsStringAsync();
|
||||
var result = JsonSerializer.Deserialize<AccessTokenResponse>(jsonContent, new JsonSerializerOptions
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower
|
||||
});
|
||||
return result;
|
||||
}, () => new DistributedCacheEntryOptions()
|
||||
{
|
||||
AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(3600)
|
||||
});
|
||||
|
||||
return output.AccessToken;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建带参数的二维码
|
||||
/// </summary>
|
||||
/// <param name="scene">场景值</param>
|
||||
/// <returns>二维码URL</returns>
|
||||
public async Task<string> CreateQrCodeAsync(string scene)
|
||||
{
|
||||
var accessToken = await GetAccessTokenAsync();
|
||||
var url = $"https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token={accessToken}";
|
||||
|
||||
var requestBody = new
|
||||
{
|
||||
action_name = "QR_STR_SCENE",
|
||||
action_info = new
|
||||
{
|
||||
scene = new
|
||||
{
|
||||
expire_seconds = 600,
|
||||
scene_str = scene
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var jsonContent = JsonSerializer.Serialize(requestBody);
|
||||
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
|
||||
|
||||
var response = await _httpClientFactory.CreateClient().PostAsync(url, content);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var result = JsonSerializer.Deserialize<QrCodeResponse>(responseContent);
|
||||
|
||||
return $"https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket={result.Ticket}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过code获取用户基础信息接口(为了获取用户access_token和openid)
|
||||
/// </summary>
|
||||
/// <param name="code">授权码</param>
|
||||
/// <returns>用户基础信息响应对象</returns>
|
||||
private async Task<UserBaseInfoResponse> GetBaseUserInfoByCodeAsync(string code)
|
||||
{
|
||||
var url = $"https://api.weixin.qq.com/sns/oauth2/access_token?appid={_options.AppId}&secret={_options.Secret}&code={code}&grant_type=authorization_code";
|
||||
|
||||
var response = await _httpClientFactory.CreateClient().GetAsync(url);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var jsonContent = await response.Content.ReadAsStringAsync();
|
||||
var result = JsonSerializer.Deserialize<UserBaseInfoResponse>(jsonContent, new JsonSerializerOptions
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过code获取用户信息接口
|
||||
/// </summary>
|
||||
/// <param name="code">授权码</param>
|
||||
/// <returns>用户信息响应对象</returns>
|
||||
public async Task<UserInfoResponse> GetUserInfoByCodeAsync(string code)
|
||||
{
|
||||
var baseUserInfo = await GetBaseUserInfoByCodeAsync(code);
|
||||
var url = $"https://api.weixin.qq.com/sns/userinfo?access_token={baseUserInfo.AccessToken}&openid={baseUserInfo.OpenId}&lang=zh_CN";
|
||||
|
||||
var response = await _httpClientFactory.CreateClient().GetAsync(url);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var jsonContent = await response.Content.ReadAsStringAsync();
|
||||
var result = JsonSerializer.Deserialize<UserInfoResponse>(jsonContent, new JsonSerializerOptions
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理回调逻辑
|
||||
/// </summary>
|
||||
/// <param name="sceneType"></param>
|
||||
/// <param name="openId"></param>
|
||||
/// <param name="bindUserId"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<SceneResultEnum> CallBackHandlerAsync(SceneTypeEnum sceneType, string openId, Guid? bindUserId)
|
||||
{
|
||||
var aiUserInfo = await _userRepository._DbQueryable.Where(x => x.FuwuhaoOpenId == openId).FirstAsync();
|
||||
switch (sceneType)
|
||||
{
|
||||
case SceneTypeEnum.LoginOrRegister:
|
||||
//有openid,说明登录成功
|
||||
if (aiUserInfo is not null)
|
||||
{
|
||||
return SceneResultEnum.Login;
|
||||
}
|
||||
//无openid,说明需要进行注册
|
||||
else
|
||||
{
|
||||
return SceneResultEnum.Register;
|
||||
}
|
||||
|
||||
break;
|
||||
case SceneTypeEnum.Bind:
|
||||
//说明已经有微信号,直接换绑
|
||||
|
||||
if (aiUserInfo is not null)
|
||||
{
|
||||
await _userRepository.DeleteByIdAsync(aiUserInfo.Id);
|
||||
}
|
||||
|
||||
if (bindUserId is null)
|
||||
{
|
||||
throw new UserFriendlyException("绑定用户,需要传入绑定的用户id");
|
||||
}
|
||||
|
||||
//说明没有绑定过,直接绑定
|
||||
await _userRepository.InsertAsync(new AiUserExtraInfoEntity(bindUserId.Value, openId));
|
||||
return SceneResultEnum.Bind;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(sceneType), sceneType, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user