当前位置:网站首页>Use abp Zero builds a third-party login module (II): server development
Use abp Zero builds a third-party login module (II): server development
2022-06-26 14:45:00 【Linxiao LX】
WeChat SDK Integration of Library
WeChat SDK The library is for wechat related API Modules to be packaged , At present, wechat is in the open source community SDK There are so many libraries , I chose a better one EasyAbp WeChat library .
Of course this library is ABP vNext Framework of the , Need a little rewriting . After encapsulation, we need the following interfaces
Applet code generation interface :
public Task<GetUnlimitedACodeResponse> GetUnlimitedACodeAsync(string scene, string page = null, short width = 430, bool autoColor = false, LineColorModel lineColor = null, bool isHyaline = false)
Get users OpenId And SessionKey The interface of
public async Task<Code2SessionResponse> Code2SessionAsync(string jsCode, string grantType = "authorization_code")
Third party login module
Abp.Zero Third party login mechanism
Let's review the third-party login in Abp.Zero How to implement in
AbpUserLogin Table storage The third party account is unique Id And in the system User Correspondence of , Pictured

At the time of landing , stay ExternalAuthenticate In the method , Delivery required Login credentials , That is to say ProviderAccessCode, This is a temporary credential , According to it, get and call the corresponding Provider Of GetUserInfo Method , Get third-party login information , Include The third party account is unique Id
Then call GetExternalUserInfo, It will go. AbpUserLogin According to The third party account is unique Id Find out if there are registered users
If you have any , Return the user information directly ;
If there is no , Register a user first , Insert correspondence . And return to the user .
The next step is the normal login process : Verify user status , Verify password , Insert login information, etc .
Write code
appsettings.json Add the configuration of wechat applet in , Good configuration AppId and AppSecret
...
"WeChat": {
"MiniProgram": {
"Token": "",
"OpenAppId": "",
"AppId": "000000000000000000",
"AppSecret": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"EncodingAesKey": ""
}
}
...Create a new one WeChatAuthProvider And inherited from ExternalAuthProviderApiBase, Write login
internal class WeChatAuthProvider : ExternalAuthProviderApiBase
{
private readonly LoginService loginService;
public WeChatAuthProvider(LoginService loginService)
{
this.loginService = loginService;
}
public override async Task<ExternalAuthUserInfo> GetUserInfo(string accessCode)
{
var result = new ExternalAuthUserInfo();
var weChatLoginResult = await loginService.Code2SessionAsync(accessCode);
// Applet call to get token Interface https://api.weixin.qq.com/cgi-bin/token Back to token Value cannot be used for web page authorization interface !
//tips:https://www.cnblogs.com/remon/p/6420418.html
//var userInfo = await loginService.GetUserInfoAsync(weChatLoginResult.OpenId);
var seed = Guid.NewGuid().ToString("N").Substring(0, 7);
result.Name = seed;
result.UserName = seed;
result.Surname = " WeChat users ";
result.ProviderKey = weChatLoginResult.OpenId;
result.Provider = nameof(WeChatAuthProvider);
return result;
}
}
WebCore In the project , take WeChatAuthProvider Sign up to Abp.Zero Third party login Providers in
The WeChat AppId and AppSecret They correspond to each other ClientId,ClientSecret
private void ConfigureExternalAuth()
{
IocManager.Register<IExternalAuthConfiguration, ExternalAuthConfiguration>();
var externalAuthConfiguration = IocManager.Resolve<IExternalAuthConfiguration>();
var appId = _appConfiguration["WeChat:MiniProgram:AppId"];
var appSecret = _appConfiguration["WeChat:MiniProgram:AppSecret"];
externalAuthConfiguration.Providers.Add(new ExternalLoginProviderInfo(
nameof(WeChatAuthProvider), appId, appSecret, typeof(WeChatAuthProvider))
);
);
}rewrite TokenAuthController.cs Medium ExternalAuthenticate Method
private async Task<ExternalAuthenticateResultModel> ExternalAuthenticate(ExternalAuthenticateModel model)
{
var externalUser = await GetExternalUserInfo(model);
// take openId Pass to ProviderKey
model.ProviderKey = externalUser.ProviderKey;
var loginResult = await _logInManager.LoginAsync(new UserLoginInfo(model.AuthProvider, model.ProviderKey, model.AuthProvider), GetTenancyNameOrNull());
switch (loginResult.Result)
{
case AbpLoginResultType.Success:
{
var accessToken = CreateAccessToken(CreateJwtClaims(loginResult.Identity));
return new ExternalAuthenticateResultModel
{
AccessToken = accessToken,
EncryptedAccessToken = GetEncryptedAccessToken(accessToken),
ExpireInSeconds = (int)_configuration.Expiration.TotalSeconds
};
}
case AbpLoginResultType.UnknownExternalLogin:
{
var newUser = await RegisterExternalUserAsync(externalUser);
if (!newUser.IsActive)
{
return new ExternalAuthenticateResultModel
{
WaitingForActivation = true
};
}
// Try to login again with newly registered user!
loginResult = await _logInManager.LoginAsync(new UserLoginInfo(model.AuthProvider, model.ProviderKey, model.AuthProvider), GetTenancyNameOrNull());
if (loginResult.Result != AbpLoginResultType.Success)
{
throw _abpLoginResultTypeHelper.CreateExceptionForFailedLoginAttempt(
loginResult.Result,
model.ProviderKey,
GetTenancyNameOrNull()
);
}
return new ExternalAuthenticateResultModel
{
AccessToken = CreateAccessToken(CreateJwtClaims(loginResult.Identity)),
ExpireInSeconds = (int)_configuration.Expiration.TotalSeconds
};
}
default:
{
throw _abpLoginResultTypeHelper.CreateExceptionForFailedLoginAttempt(
loginResult.Result,
model.ProviderKey,
GetTenancyNameOrNull()
);
}
}
}
rewrite TokenAuthController.cs Medium GetExternalUserInfo Method
private async Task<ExternalAuthUserInfo> GetExternalUserInfo(ExternalAuthenticateModel model)
{
var userInfo = await _externalAuthManager.GetUserInfo(model.AuthProvider, model.ProviderAccessCode);
//if (userInfo.ProviderKey != model.ProviderKey)
//{
// throw new UserFriendlyException(L("CouldNotValidateExternalUser"));
//}
return userInfo;
}Authentication status verification module
We need to maintain the authentication status throughout the authentication login process (Status), In the access to Login credentials AccessCode Write the value in time after .
The authentication status will have :
CREATED: Established , Wait for the user to scan the code
ACCESSED: Scanned code , Wait for the user to confirm the authorization
AUTHORIZED: Authorized to complete
EXPIRED: Applet code is out of date , Has lapsed
We need to build a cache , To store the above values
establish WechatMiniappLoginTokenCacheItem, Create separate Status Properties and ProviderAccessCode
public class WechatMiniappLoginTokenCacheItem
{
public string Status { get; set; }
public string ProviderAccessCode { get; set; }
}Create cache type WechatMiniappLoginTokenCache.
public class WechatMiniappLoginTokenCache : MemoryCacheBase<WechatMiniappLoginTokenCacheItem>, ISingletonDependency
{
public WechatMiniappLoginTokenCache() : base(nameof(WechatMiniappLoginTokenCache))
{
}
}stay Domain New in the project MiniappManager Class as a domain service , And injection ACodeService Wechat applet code generation service and WechatMiniappLoginTokenCache Cache object
public class MiniappManager : DomainService
{
private readonly ACodeService aCodeService;
private readonly WechatMiniappLoginTokenCache wechatMiniappLoginTokenCache;
public MiniappManager(ACodeService aCodeService,
WechatMiniappLoginTokenCache wechatMiniappLoginTokenCache)
{
this.aCodeService=aCodeService;
this.wechatMiniappLoginTokenCache=wechatMiniappLoginTokenCache;
}
...
}Set up separately SetTokenAsync,GetTokenAsync and CheckTokenAsync, Set up separately Token Corresponding value , obtain Token Corresponding value and Token Check the validity of the corresponding value
public virtual async Task<WechatMiniappLoginTokenCacheItem> GetTokenAsync(string token)
{
var cacheItem = await wechatMiniappLoginTokenCache.GetAsync(token, null);
return cacheItem;
}
public virtual async Task SetTokenAsync(string token, string status, string providerAccessCode, bool isCheckToken = true, DateTimeOffset? absoluteExpireTime = null)
{
if (isCheckToken)
{
await this.CheckTokenAsync(token);
}
await wechatMiniappLoginTokenCache.SetAsync(token, new WechatMiniappLoginTokenCacheItem()
{
Status=status,
ProviderAccessCode=providerAccessCode
}, absoluteExpireTime: absoluteExpireTime);
}
public virtual async Task CheckTokenAsync(string token)
{
var cacheItem = await wechatMiniappLoginTokenCache.GetAsync(token, null);
if (cacheItem == null)
{
throw new UserFriendlyException("WechatMiniappLoginInvalidToken",
" Wechat applet login Token illegal ");
}
else
{
if (cacheItem.Status=="AUTHORIZED")
{
throw new UserFriendlyException("WechatMiniappLoginInvalidToken",
" Wechat applet login Token Has lapsed ");
}
}
}To write GetACodeAsync, Generate wechat applet code
public async Task<byte[]> GetACodeAsync(string token, string page, DateTimeOffset? absoluteExpireTime = null)
{
await wechatMiniappLoginTokenCache.SetAsync(token, new WechatMiniappLoginTokenCacheItem()
{
Status="CREATED",
},
absoluteExpireTime: absoluteExpireTime);
var result = await aCodeService.GetUnlimitedACodeAsync(token, page);
return result.BinaryData;
}After generation, it will Token Write value to cache , The status is CREATED, The corresponding page is “ Scanned code ”
Later on byte[] Method to return the applet code image
To write Api Interface
stay Application New in the project MiniappAppService Class as a domain service , And injection MiniappManager object
[AbpAllowAnonymous]
//[AbpAuthorize(PermissionNames.Pages_Wechat)]
public class MiniappAppService : AppServiceBase
{
public static TimeSpan TokenCacheDuration = TimeSpan.FromMinutes(5);
public static TimeSpan AuthCacheDuration = TimeSpan.FromMinutes(5);
private readonly MiniappManager miniappManager;
public MiniappAppService(MiniappManager miniappManager)
{
this.miniappManager=miniappManager;
}
...
}Compile each method
[HttpGet]
[WrapResult(WrapOnSuccess = false, WrapOnError = false)]
public async Task<IActionResult> GetACodeAsync(GetACodeAsyncInput input)
{
var mode = input.Mode;
var result = await miniappManager.GetACodeAsync(input.Scene, input.Page, DateTimeOffset.Now.Add(TokenCacheDuration));
return new FileContentResult(result, MimeTypeNames.ImagePng);
}
[HttpGet]
[AbpAllowAnonymous]
public virtual async Task<WechatMiniappLoginTokenCacheItem> GetTokenAsync(string token)
{
var cacheItem = await miniappManager.GetTokenAsync(token);
return cacheItem;
}
[AbpAllowAnonymous]
public virtual async Task AccessAsync(string token)
{
await miniappManager.SetTokenAsync(token, "ACCESSED", null, true, DateTimeOffset.Now.Add(AuthCacheDuration));
}
[AbpAllowAnonymous]
public virtual async Task AuthenticateAsync(ChangeStatusInput input)
{
await miniappManager.SetTokenAsync(input.Token, "AUTHORIZED", input.ProviderAccessCode, true, DateTimeOffset.Now.Add(TimeSpan.FromMinutes(1)));
}GetACodeAsync: Get the applet code Api,
GetTokenAsync: obtain Token Corresponding value Api,
AccessAsync: Code scanned call Api,
AuthenticateAsync: Authorized to call Api,

thus , All server interfaces have been completed
边栏推荐
- 在线牛人博主
- C语言基础知识入门(大全)「建议收藏」
- GDAL and opencv smooth and blur TIF images
- What is the ranking of Guosen Securities? Is it safe to open a stock account?
- Sword finger offer 18.22.25.52 Double pointer (simple)
- Usage of unique function
- C language | the difference between heap and stack
- Leaflet loading ArcGIS for server map layers
- Mathematical modeling of war preparation 30 regression analysis 2
- From Celsius to the three arrows: encrypting the domino of the ten billion giants, and drying up the epic liquidity
猜你喜欢
随机推荐
C language | Consortium
MHA high availability coordination and failover
Can wptx64 be uninstalled_ Which software of win10 can be uninstalled
Datasets dataset class (2)
ArcGIS secondary development - arcpy delete layer
Usage of unique function
【async/await】--异步编程最终解决方案
Complete diagram / Euler loop
聊聊 RPA 方向的规划:简单有价值的事情长期坚持做
710. 黑名单中的随机数
备战数学建模31-数据插值与曲线拟合3
Atcoder bit operation & Conclusion + formula derivation
Numpy基本使用
Sword finger offer 40.41 Sort (medium)
权威发布 | 延安大学2022年教师岗位招聘公告
IP certificate application process of sectigo
How to mount cloud disks in ECS
How to personalize VIM editor format (DIY)
Common controls and custom controls
Sword finger offer 21.57.58 I Double pointer (simple)









