Browse Source

增加微信注册接口,通过微信注册的用户写入到UserLogin

pull/7/head
cKey 6 years ago
parent
commit
f04afcd982
  1. 2
      aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/PhoneNumberRegisterDto.cs
  2. 28
      aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/WeChatRegisterDto.cs
  3. 4
      aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/IAccountAppService.cs
  4. 1
      aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN.Abp.Account.Application.csproj
  5. 6
      aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AbpAccountApplicationModule.cs
  6. 35
      aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AccountAppService.cs
  7. 3
      aspnet-core/modules/account/LINGYUN.Abp.Account.Domain/LINGYUN/Abp/Account/Localization/Resources/en.json
  8. 3
      aspnet-core/modules/account/LINGYUN.Abp.Account.Domain/LINGYUN/Abp/Account/Localization/Resources/zh-Hans.json
  9. 17
      aspnet-core/modules/account/LINGYUN.Abp.Account.HttpApi/LINGYUN/Abp/Account/AccountController.cs
  10. 7
      aspnet-core/modules/common/LINGYUN.Abp.Aliyun.Authorization/LINGYUN.Abp.Aliyun.Authorization.csproj
  11. 2
      aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunModule.cs
  12. 5
      aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/AbpIdentityServerWeChatValidatorModule.cs
  13. 30
      aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/WeChatValidator/WeChatTokenGrantValidator.cs
  14. 32
      aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/System/Net/Http/HttpClientTokenRequestExtensions.cs
  15. 48
      aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/System/Net/Http/WeChatOpenIdResponse.cs
  16. 4
      aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/AbpWeChatAuthorizationModule.cs
  17. 9
      aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/OpenId/IWeChatOpenIdFinder.cs
  18. 30
      aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/OpenId/WeChatOpenId.cs
  19. 28
      aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/OpenId/WeChatOpenIdCacheItem.cs
  20. 97
      aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/OpenId/WeChatOpenIdFinder.cs
  21. 2
      aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/OpenId/WeChatOpenIdRequest.cs
  22. 63
      aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/OpenId/WeChatOpenIdResponse.cs
  23. 0
      aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/Token/IWeChatTokenProvider.cs
  24. 0
      aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/Token/WeChatToken.cs
  25. 0
      aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/Token/WeChatTokenCacheItem.cs
  26. 2
      aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/Token/WeChatTokenProvider.cs
  27. 0
      aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/Token/WeChatTokenRequest.cs
  28. 0
      aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/Token/WeChatTokenResponse.cs
  29. 19
      aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/System/Net/Http/HttpClientWeChatTokenRequestExtensions.cs

2
aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/RegisterVerifyDto.cs → aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/PhoneNumberRegisterDto.cs

@ -4,7 +4,7 @@ using Volo.Abp.Identity;
namespace LINGYUN.Abp.Account
{
public class RegisterVerifyDto
public class PhoneNumberRegisterDto
{
[Required]
[Phone]

28
aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/WeChatRegisterDto.cs

@ -0,0 +1,28 @@
using System.ComponentModel.DataAnnotations;
using Volo.Abp.Auditing;
using Volo.Abp.Identity;
namespace LINGYUN.Abp.Account
{
public class WeChatRegisterDto
{
[Required]
public string Code { get; set; }
[DisableAuditing]
[DataType(DataType.Password)]
[Required]
[StringLength(IdentityUserConsts.MaxPasswordLength)]
public string Password { get; set; }
[StringLength(IdentityUserConsts.MaxNameLength)]
public string Name { get; set; }
[StringLength(IdentityUserConsts.MaxUserNameLength)]
public string UserName { get; set; }
[EmailAddress]
[StringLength(IdentityUserConsts.MaxEmailLength)]
public string EmailAddress { get; set; }
}
}

4
aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/IAccountAppService.cs

@ -6,7 +6,9 @@ namespace LINGYUN.Abp.Account
{
public interface IAccountAppService : IApplicationService
{
Task<IdentityUserDto> RegisterAsync(RegisterVerifyDto input);
Task<IdentityUserDto> RegisterAsync(PhoneNumberRegisterDto input);
Task<IdentityUserDto> RegisterAsync(WeChatRegisterDto input);
Task ResetPasswordAsync(PasswordResetDto passwordReset);

1
aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN.Abp.Account.Application.csproj

@ -11,6 +11,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\common\LINGYUN.Abp.WeChat.Authorization\LINGYUN.Abp.WeChat.Authorization.csproj" />
<ProjectReference Include="..\LINGYUN.Abp.Account.Application.Contracts\LINGYUN.Abp.Account.Application.Contracts.csproj" />
<ProjectReference Include="..\LINGYUN.Abp.Account.Domain\LINGYUN.Abp.Account.Domain.csproj" />
</ItemGroup>

6
aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AbpAccountApplicationModule.cs

@ -1,11 +1,13 @@
using Volo.Abp.Modularity;
using LINGYUN.Abp.WeChat.Authorization;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.Account
{
[DependsOn(
typeof(AbpAccountDomainModule),
typeof(Volo.Abp.Account.AbpAccountApplicationModule),
typeof(AbpAccountApplicationContractsModule))]
typeof(AbpAccountApplicationContractsModule),
typeof(AbpWeChatAuthorizationModule))]
public class AbpAccountApplicationModule : AbpModule
{

35
aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AccountAppService.cs

@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Identity;
using LINGYUN.Abp.WeChat.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Caching.Distributed;
using System;
using System.Threading.Tasks;
@ -8,8 +9,6 @@ using Volo.Abp.Caching;
using Volo.Abp.Identity;
using Volo.Abp.Settings;
using Volo.Abp.Sms;
using Volo.Abp.Uow;
using Microsoft.AspNetCore.Cryptography;
namespace LINGYUN.Abp.Account
{
@ -18,6 +17,8 @@ namespace LINGYUN.Abp.Account
/// </summary>
public class AccountAppService : ApplicationService, IAccountAppService
{
private IWeChatOpenIdFinder _weChatOpenIdFinder;
protected IWeChatOpenIdFinder WeChatOpenIdFinder => LazyGetRequiredService(ref _weChatOpenIdFinder);
protected ISmsSender SmsSender { get; }
protected IdentityUserManager UserManager { get; }
protected IdentityUserStore UserStore { get; }
@ -40,6 +41,32 @@ namespace LINGYUN.Abp.Account
PhoneNumberTokenProvider = phoneNumberTokenProvider;
LocalizationResource = typeof(Localization.AccountResource);
}
public virtual async Task<IdentityUserDto> RegisterAsync(WeChatRegisterDto input)
{
await CheckSelfRegistrationAsync();
var wehchatOpenId = await WeChatOpenIdFinder.FindAsync(input.Code);
var user = await UserManager.FindByLoginAsync("WeChat", wehchatOpenId.OpenId);
if (user == null)
{
var userName = input.UserName ?? wehchatOpenId.OpenId;
var userEmail = input.EmailAddress ?? $"{userName}@{new Random().Next(1000, 99999)}.com";//如果邮件地址不验证,随意写入一个
user = new IdentityUser(GuidGenerator.Create(), userName, userEmail, CurrentTenant.Id)
{
Name = input.Name ?? userName
};
(await UserManager.CreateAsync(user, input.Password)).CheckErrors();
(await UserManager.AddDefaultRolesAsync(user)).CheckErrors();
var userLogin = new UserLoginInfo("WeChat", wehchatOpenId.OpenId, "微信认证登录");
(await UserManager.AddLoginAsync(user, userLogin)).CheckErrors();
}
return ObjectMapper.Map<IdentityUser, IdentityUserDto>(user);
}
/// <summary>
/// 用户注册
/// </summary>
@ -50,7 +77,7 @@ namespace LINGYUN.Abp.Account
/// 如果没有此手机号的缓存记录或验证码不匹配,抛出验证码无效的异常
/// 用户注册成功,清除缓存的验证码记录
/// </remarks>
public virtual async Task<IdentityUserDto> RegisterAsync(RegisterVerifyDto input)
public virtual async Task<IdentityUserDto> RegisterAsync(PhoneNumberRegisterDto input)
{
var phoneVerifyCacheKey = NormalizeCacheKey(input.PhoneNumber);

3
aspnet-core/modules/account/LINGYUN.Abp.Account.Domain/LINGYUN/Abp/Account/Localization/Resources/en.json

@ -14,6 +14,7 @@
"Description:PhoneVerifyCodeExpiration": "The valid time for the user to send SMS verification code, unit m, default 3m",
"RequiredEmailAddress": "Email address required",
"InvalidPhoneNumber": "Invalid phone number",
"DuplicatePhoneNumber": "The phone number {0} has been registered!"
"DuplicatePhoneNumber": "The phone number {0} has been registered!",
"DuplicateWeChat": "The wechat has been registered!"
}
}

3
aspnet-core/modules/account/LINGYUN.Abp.Account.Domain/LINGYUN/Abp/Account/Localization/Resources/zh-Hans.json

@ -14,6 +14,7 @@
"Description:PhoneVerifyCodeExpiration": "用户发送短信验证码的有效时长,单位m,默认3m",
"RequiredEmailAddress": "邮件地址必须输入",
"InvalidPhoneNumber": "手机号无效",
"DuplicatePhoneNumber": "手机号已经注册过!"
"DuplicatePhoneNumber": "手机号已经注册过!",
"DuplicateWeChat": "微信号已经注册过!"
}
}

17
aspnet-core/modules/account/LINGYUN.Abp.Account.HttpApi/LINGYUN/Abp/Account/AccountController.cs

@ -9,7 +9,7 @@ namespace LINGYUN.Abp.Account
{
[RemoteService(Name = AccountRemoteServiceConsts.RemoteServiceName)]
[Area("account")]
[Route("api/account/phone")]
[Route("api/account")]
public class AccountController : AbpController, IAccountAppService
{
protected IAccountAppService AccountAppService { get; }
@ -20,21 +20,28 @@ namespace LINGYUN.Abp.Account
}
[HttpPost]
[Route("register")]
public virtual async Task<IdentityUserDto> RegisterAsync(RegisterVerifyDto input)
[Route("wechat/register")]
public virtual async Task<IdentityUserDto> RegisterAsync(WeChatRegisterDto input)
{
return await AccountAppService.RegisterAsync(input);
}
[HttpPost]
[Route("verify")]
[Route("phone/register")]
public virtual async Task<IdentityUserDto> RegisterAsync(PhoneNumberRegisterDto input)
{
return await AccountAppService.RegisterAsync(input);
}
[HttpPost]
[Route("phone/verify")]
public virtual async Task VerifyPhoneNumberAsync(VerifyDto input)
{
await AccountAppService.VerifyPhoneNumberAsync(input);
}
[HttpPut]
[Route("reset-password")]
[Route("phone/reset-password")]
public virtual async Task ResetPasswordAsync(PasswordResetDto passwordReset)
{
await AccountAppService.ResetPasswordAsync(passwordReset);

7
aspnet-core/modules/common/LINGYUN.Abp.Aliyun.Authorization/LINGYUN.Abp.Aliyun.Authorization.csproj

@ -3,6 +3,13 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>2.9.0</Version>
<Authors>LINGYUN</Authors>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<OutputPath>D:\LocalNuget</OutputPath>
</PropertyGroup>
<ItemGroup>

2
aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunModule.cs

@ -23,7 +23,7 @@ namespace LINGYUN.Abp.BlobStoring.Aliyun
{
containerConfiguration.UseAliyun(aliyun =>
{
aliyun.BucketName = configuration[AliyunBlobProviderConfigurationNames.BucketName];
aliyun.BucketName = configuration[AliyunBlobProviderConfigurationNames.BucketName] ?? "";
aliyun.CreateBucketIfNotExists = configuration.GetSection(AliyunBlobProviderConfigurationNames.CreateBucketIfNotExists).Get<bool>();
aliyun.CreateBucketReferer = configuration.GetSection(AliyunBlobProviderConfigurationNames.CreateBucketReferer).Get<List<string>>();
aliyun.Endpoint = configuration[AliyunBlobProviderConfigurationNames.Endpoint];

5
aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/AbpIdentityServerWeChatValidatorModule.cs

@ -28,11 +28,6 @@ namespace LINGYUN.Abp.IdentityServer
Configure<WeChatSignatureOptions>(configuration.GetSection("WeChat:Signature"));
context.Services.AddHttpClient(WeChatValidatorConsts.WeChatValidatorClientName, options =>
{
options.BaseAddress = new System.Uri("https://api.weixin.qq.com/sns/jscode2session");
});
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpIdentityServerWeChatValidatorModule>();

30
aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/WeChatValidator/WeChatTokenGrantValidator.cs

@ -26,6 +26,7 @@ namespace LINGYUN.Abp.IdentityServer.WeChatValidator
protected AbpWeChatOptions Options { get; }
protected IHttpClientFactory HttpClientFactory{ get; }
protected IEventService EventService { get; }
protected IWeChatOpenIdFinder WeChatOpenIdFinder { get; }
protected IIdentityUserRepository UserRepository { get; }
protected UserManager<IdentityUser> UserManager { get; }
protected SignInManager<IdentityUser> SignInManager { get; }
@ -35,6 +36,7 @@ namespace LINGYUN.Abp.IdentityServer.WeChatValidator
public WeChatTokenGrantValidator(
IEventService eventService,
IWeChatOpenIdFinder weChatOpenIdFinder,
IHttpClientFactory httpClientFactory,
UserManager<IdentityUser> userManager,
IIdentityUserRepository userRepository,
@ -52,6 +54,7 @@ namespace LINGYUN.Abp.IdentityServer.WeChatValidator
SignInManager = signInManager;
Localizer = stringLocalizer;
UserRepository = userRepository;
WeChatOpenIdFinder = weChatOpenIdFinder;
HttpClientFactory = httpClientFactory;
PhoneNumberTokenProvider = phoneNumberTokenProvider;
}
@ -77,28 +80,11 @@ namespace LINGYUN.Abp.IdentityServer.WeChatValidator
Localizer["InvalidGrant:WeChatCodeNotFound"]);
return;
}
var httpClient = HttpClientFactory.CreateClient(WeChatValidatorConsts.WeChatValidatorClientName);
var httpRequest = new WeChatOpenIdRequest
{
Code = wechatCode,
AppId = Options.AppId,
Secret = Options.AppSecret,
BaseUrl = httpClient.BaseAddress.AbsoluteUri
};
var wechatOpenIdResponse = await httpClient.RequestWeChatCodeTokenAsync(httpRequest);
if (wechatOpenIdResponse.IsError)
{
Logger.LogWarning("Authentication failed for token: {0}, reason: invalid token", wechatCode);
Logger.LogWarning("WeChat auth failed, error: {0}", wechatOpenIdResponse.ErrorMessage);
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant,
Localizer["InvalidGrant:WeChatTokenInvalid"]);
return;
}
var currentUser = await UserManager.FindByNameAsync(wechatOpenIdResponse.OpenId);
var whchatOpenId = await WeChatOpenIdFinder.FindAsync(wechatCode);
var currentUser = await UserManager.FindByLoginAsync("WeChat", whchatOpenId.OpenId);
if(currentUser == null)
{
Logger.LogWarning("Invalid grant type: wechat openid: {0} not register", wechatOpenIdResponse.OpenId);
Logger.LogWarning("Invalid grant type: wechat openid: {0} not register", whchatOpenId.OpenId);
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant,
Localizer["InvalidGrant:WeChatNotRegister"]);
return;
@ -110,9 +96,9 @@ namespace LINGYUN.Abp.IdentityServer.WeChatValidator
{
additionalClaims.Add(new Claim(AbpClaimTypes.TenantId, currentUser.TenantId?.ToString()));
}
additionalClaims.Add(new Claim(WeChatValidatorConsts.ClaimTypes.OpenId, wechatOpenIdResponse.OpenId));
additionalClaims.Add(new Claim(WeChatValidatorConsts.ClaimTypes.OpenId, whchatOpenId.OpenId));
await EventService.RaiseAsync(new UserLoginSuccessEvent(currentUser.UserName, wechatOpenIdResponse.OpenId, null));
await EventService.RaiseAsync(new UserLoginSuccessEvent(currentUser.UserName, whchatOpenId.OpenId, null));
context.Result = new GrantValidationResult(sub,
WeChatValidatorConsts.AuthenticationMethods.BasedWeChatAuthentication, additionalClaims.ToArray());
}

32
aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/System/Net/Http/HttpClientTokenRequestExtensions.cs

@ -1,32 +0,0 @@
using IdentityModel.Client;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace System.Net.Http
{
public static class HttpClientTokenRequestExtensions
{
public static async Task<WeChatOpenIdResponse> RequestWeChatCodeTokenAsync(this HttpMessageInvoker client, WeChatOpenIdRequest request, CancellationToken cancellationToken = default)
{
var getResuestUrlBuiilder = new StringBuilder();
getResuestUrlBuiilder.Append(request.BaseUrl);
getResuestUrlBuiilder.AppendFormat("?appid={0}", request.AppId);
getResuestUrlBuiilder.AppendFormat("&secret={0}", request.Secret);
getResuestUrlBuiilder.AppendFormat("&js_code={0}", request.Code);
getResuestUrlBuiilder.Append("&grant_type=authorization_code");
var getRequest = new HttpRequestMessage(HttpMethod.Get, getResuestUrlBuiilder.ToString());
HttpResponseMessage httpResponse;
try
{
httpResponse = await client.SendAsync(getRequest, cancellationToken).ConfigureAwait(false);
}
catch (Exception ex)
{
return ProtocolResponse.FromException<WeChatOpenIdResponse>(ex);
}
return await ProtocolResponse.FromHttpResponseAsync<WeChatOpenIdResponse>(httpResponse).ConfigureAwait(false);
}
}
}

48
aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/System/Net/Http/WeChatOpenIdResponse.cs

@ -1,48 +0,0 @@
using IdentityModel.Client;
namespace System.Net.Http
{
public class WeChatOpenIdResponse : ProtocolResponse
{
/// <summary>
/// 用户唯一标识
/// </summary>
public string OpenId => TryGet("openid");
/// <summary>
/// 会话密钥
/// </summary>
/// <remarks>
/// 仅仅只是要一个openid,这个没多大用吧
/// </remarks>
public string SessionKey => TryGet("session_key");
/// <summary>
/// 用户在开放平台的唯一标识符,在满足 UnionID 下发条件的情况下会返回
/// </summary>
public string UnionId => TryGet("unionid");
/// <summary>
/// 微信认证成功没有errorcode或者errorcode为0
/// </summary>
public new bool IsError => !ErrorCode.IsNullOrWhiteSpace() && !"0".Equals(ErrorCode);
/// <summary>
/// 错误码
/// </summary>
public string ErrorCode => TryGet("errcode");
/// <summary>
/// 错误信息
/// </summary>
public new string ErrorMessage
{
get
{
return ErrorCode switch
{
"-1" => "系统繁忙,此时请开发者稍候再试",
"0" => string.Empty,
"40029" => "code 无效",
"45011" => "频率限制,每个用户每分钟100次",
_ => "未知的异常",
};
}
}
}
}

4
aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/AbpWeChatAuthorizationModule.cs

@ -15,9 +15,9 @@ namespace LINGYUN.Abp.WeChat.Authorization
var configuration = context.Services.GetConfiguration();
Configure<AbpWeChatOptions>(configuration.GetSection("WeChat:Auth"));
context.Services.AddHttpClient("WeChatTokenProviderClient", options =>
context.Services.AddHttpClient("WeChatRequestClient", options =>
{
options.BaseAddress = new Uri("https://api.weixin.qq.com/cgi-bin/token");
options.BaseAddress = new Uri("https://api.weixin.qq.com");
}).AddTransientHttpErrorPolicy(builder =>
builder.WaitAndRetryAsync(3, i => TimeSpan.FromSeconds(Math.Pow(2, i))));
}

9
aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/OpenId/IWeChatOpenIdFinder.cs

@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace LINGYUN.Abp.WeChat.Authorization
{
public interface IWeChatOpenIdFinder
{
Task<WeChatOpenId> FindAsync(string code);
}
}

30
aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/OpenId/WeChatOpenId.cs

@ -0,0 +1,30 @@
namespace LINGYUN.Abp.WeChat.Authorization
{
public class WeChatOpenId
{
/// <summary>
/// 用户在开放平台的唯一标识符,在满足 UnionID 下发条件的情况下会返回
/// </summary>
public string UnionId { get; set; }
/// <summary>
/// 用户唯一标识
/// </summary>
public string OpenId { get; set; }
/// <summary>
/// 会话密钥
/// </summary>
public string SessionKey { get; set; }
public WeChatOpenId()
{
}
public WeChatOpenId(string openId, string sessionKey, string unionId = null)
{
OpenId = openId;
SessionKey = sessionKey;
UnionId = unionId;
}
}
}

28
aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/OpenId/WeChatOpenIdCacheItem.cs

@ -0,0 +1,28 @@
using System;
namespace LINGYUN.Abp.WeChat.Authorization
{
public class WeChatOpenIdCacheItem
{
public string Code { get; set; }
public WeChatOpenId WeChatOpenId { get; set; }
public WeChatOpenIdCacheItem()
{
}
public WeChatOpenIdCacheItem(string code, WeChatOpenId weChatOpenId)
{
Code = code;
WeChatOpenId = weChatOpenId;
}
public static string CalculateCacheKey(string code, Guid? tenantId = null)
{
string tenant = tenantId != null ? tenantId.Value.ToString("D") : "host";
return "t:" + tenant + ",c:" + code;
}
}
}

97
aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/OpenId/WeChatOpenIdFinder.cs

@ -0,0 +1,97 @@
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Json;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.WeChat.Authorization
{
[Dependency(ServiceLifetime.Singleton, ReplaceServices = true)]
[ExposeServices(typeof(IWeChatOpenIdFinder))]
public class WeChatOpenIdFinder : IWeChatOpenIdFinder
{
public ILogger<WeChatOpenIdFinder> Logger { get; set; }
protected AbpWeChatOptions Options { get; }
protected ICurrentTenant CurrentTenant { get; }
protected IHttpClientFactory HttpClientFactory { get; }
protected IJsonSerializer JsonSerializer { get; }
protected IDistributedCache<WeChatOpenIdCacheItem> Cache { get; }
public WeChatOpenIdFinder(
ICurrentTenant currentTenant,
IJsonSerializer jsonSerializer,
IHttpClientFactory httpClientFactory,
IOptions<AbpWeChatOptions> options,
IDistributedCache<WeChatOpenIdCacheItem> cache)
{
CurrentTenant = currentTenant;
JsonSerializer = jsonSerializer;
HttpClientFactory = httpClientFactory;
Cache = cache;
Options = options.Value;
Logger = NullLogger<WeChatOpenIdFinder>.Instance;
}
public virtual async Task<WeChatOpenId> FindAsync(string code)
{
return (await GetCacheItemAsync(code, CurrentTenant.Id)).WeChatOpenId;
}
protected virtual async Task<WeChatOpenIdCacheItem> GetCacheItemAsync(string code, Guid? tenantId = null)
{
var cacheKey = WeChatOpenIdCacheItem.CalculateCacheKey(code, tenantId);
Logger.LogDebug($"WeChatOpenIdFinder.GetCacheItemAsync: {cacheKey}");
var cacheItem = await Cache.GetAsync(cacheKey);
if (cacheItem != null)
{
Logger.LogDebug($"Found in the cache: {cacheKey}");
return cacheItem;
}
Logger.LogDebug($"Not found in the cache, getting from the httpClient: {cacheKey}");
var client = HttpClientFactory.CreateClient("WeChatRequestClient");
var request = new WeChatOpenIdRequest
{
BaseUrl = client.BaseAddress.AbsoluteUri,
AppId = Options.AppId,
Secret = Options.AppSecret,
Code = code
};
var response = await client.RequestWeChatOpenIdAsync(request);
var responseContent = await response.Content.ReadAsStringAsync();
var weChatOpenIdResponse = JsonSerializer.Deserialize<WeChatOpenIdResponse>(responseContent);
var weChatOpenId = weChatOpenIdResponse.ToWeChatOpenId();
cacheItem = new WeChatOpenIdCacheItem(code, weChatOpenId);
Logger.LogDebug($"Setting the cache item: {cacheKey}");
var cacheOptions = new DistributedCacheEntryOptions
{
// 微信官方文档表示 session_key的有效期是3天
// https://developers.weixin.qq.com/community/develop/doc/000c2424654c40bd9c960e71e5b009
AbsoluteExpiration = DateTimeOffset.Now.AddDays(3)
// SlidingExpiration = TimeSpan.FromDays(3),
};
await Cache.SetAsync(cacheKey, cacheItem, cacheOptions);
Logger.LogDebug($"Finished setting the cache item: {cacheKey}");
return cacheItem;
}
}
}

2
aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/System/Net/Http/WeChatOpenIdRequest.cs → aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/OpenId/WeChatOpenIdRequest.cs

@ -1,4 +1,4 @@
namespace System.Net.Http
namespace LINGYUN.Abp.WeChat.Authorization
{
public class WeChatOpenIdRequest
{

63
aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/OpenId/WeChatOpenIdResponse.cs

@ -0,0 +1,63 @@
using Newtonsoft.Json;
using System;
using Volo.Abp;
namespace LINGYUN.Abp.WeChat.Authorization
{
/// <summary>
/// 微信OpenId返回对象
/// </summary>
public class WeChatOpenIdResponse
{
/// <summary>
/// 错误码
/// </summary>
[JsonProperty("errcode")]
public string ErrorCode { get; set; }
/// <summary>
/// 会话密钥
/// </summary>
[JsonProperty("session_key")]
public string SessionKey { get; set; }
/// <summary>
/// 用户唯一标识
/// </summary>
[JsonProperty("openid")]
public string OpenId { get; set; }
/// <summary>
/// 用户在开放平台的唯一标识符,在满足 UnionID 下发条件的情况下会返回
/// </summary>
[JsonProperty("unionid")]
public string UnionId { get; set; }
/// <summary>
/// 错误消息
/// </summary>
public string ErrorMessage
{
get
{
switch (ErrorCode)
{
case "-1": return "系统繁忙,此时请开发者稍候再试";
case "0": return string.Empty;
case "40029": return "code 无效";
case "45011": return "频率限制,每个用户每分钟100次";
default: return "未知的异常,请重试";
};
}
}
/// <summary>
/// 微信认证成功没有errorcode或者errorcode为0
/// </summary>
public bool IsError => !ErrorCode.IsNullOrWhiteSpace() && !"0".Equals(ErrorCode);
public WeChatOpenId ToWeChatOpenId()
{
if(IsError)
{
throw new AbpException(ErrorMessage);
}
return new WeChatOpenId(OpenId, SessionKey, UnionId);
}
}
}

0
aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/IWeChatTokenProvider.cs → aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/Token/IWeChatTokenProvider.cs

0
aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/WeChatToken.cs → aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/Token/WeChatToken.cs

0
aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/WeChatTokenCacheItem.cs → aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/Token/WeChatTokenCacheItem.cs

2
aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/WeChatTokenProvider.cs → aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/Token/WeChatTokenProvider.cs

@ -54,7 +54,7 @@ namespace LINGYUN.Abp.WeChat.Authorization
Logger.LogDebug($"Not found in the cache, getting from the httpClient: {cacheKey}");
var client = HttpClientFactory.CreateClient("WeChatTokenProviderClient");
var client = HttpClientFactory.CreateClient("WeChatRequestClient");
var request = new WeChatTokenRequest
{

0
aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/WeChatTokenRequest.cs → aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/Token/WeChatTokenRequest.cs

0
aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/WeChatTokenResponse.cs → aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/Token/WeChatTokenResponse.cs

19
aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/System/Net/Http/HttpClientWeChatTokenRequestExtensions.cs

@ -11,6 +11,7 @@ namespace System.Net.Http
{
var getResuestUrlBuilder = new StringBuilder();
getResuestUrlBuilder.Append(request.BaseUrl);
getResuestUrlBuilder.Append("cgi-bin/token");
getResuestUrlBuilder.Append("?grant_type=client_credential");
getResuestUrlBuilder.AppendFormat("&appid={0}", request.AppId);
getResuestUrlBuilder.AppendFormat("&secret={0}", request.AppSecret);
@ -22,5 +23,23 @@ namespace System.Net.Http
return httpResponse;
}
public static async Task<HttpResponseMessage> RequestWeChatOpenIdAsync(this HttpMessageInvoker client, WeChatOpenIdRequest request, CancellationToken cancellationToken = default)
{
var getResuestUrlBuiilder = new StringBuilder();
getResuestUrlBuiilder.Append(request.BaseUrl);
getResuestUrlBuiilder.Append("sns/jscode2session");
getResuestUrlBuiilder.AppendFormat("?appid={0}", request.AppId);
getResuestUrlBuiilder.AppendFormat("&secret={0}", request.Secret);
getResuestUrlBuiilder.AppendFormat("&js_code={0}", request.Code);
getResuestUrlBuiilder.Append("&grant_type=authorization_code");
var getRequest = new HttpRequestMessage(HttpMethod.Get, getResuestUrlBuiilder.ToString());
HttpResponseMessage httpResponse;
httpResponse = await client.SendAsync(getRequest, cancellationToken).ConfigureAwait(false);
return httpResponse;
}
}
}

Loading…
Cancel
Save