当前位置:网站首页>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
边栏推荐
- 【soloπ】adb连接单个多个手机
- Sword finger offer 40.41 Sort (medium)
- 一个快速切换一个底层实现的思路分享
- 国信证券的排名如何?办理股票开户安全吗?
- Leaflet loading ArcGIS for server map layers
- 在云服务器中云磁盘如何挂载
- Naacl2022: (code practice) good visual guidance promotes better feature extraction, multimodal named entity recognition (with source code download)
- C | analysis of malloc implementation
- 挖财注册开户安全吗,有没有什么风险?
- GDAL multiband synthesis tool
猜你喜欢

MySQL master-slave replication and read-write separation

Electron

【使用yarn运行报错】The engine “node“ is incompatible with this module.

NAACL2022:(代码实践)好的视觉引导促进更好的特征提取,多模态命名实体识别(附源代码下载)...

Where do people get their top energy?

ArcGIS batch export layer script

Sword finger offer 05.58 Ⅱ string

Common evaluation indexes of classification model -- confusion matrix and ROC curve

Complimentary Book Cognitive Control: how does our brain accomplish tasks?

Electron
随机推荐
在云服务器中云磁盘如何挂载
Where do people get their top energy?
网上股票开户安不安全?谁给回答一下
One article of the quantification framework backtrader read observer
【使用yarn运行报错】The engine “node“ is incompatible with this module.
MHA high availability coordination and failover
C | analysis of malloc implementation
Usage of unique function
Practical website recommendations worth collecting for College Students
1075 pat judge (25 points)
When drawing with origin, capital letter C will appear in the upper left corner of the chart. The removal method is as follows:
人的顶级能量从哪里获取?
Leaflet load day map
Stream常用操作以及原理探索
Knowledge about adsorption
备战数学建模32-相关性分析2
Heap optimization dijkstra/hash table storage node number
Sword finger offer 21.57.58 I Double pointer (simple)
C language | Consortium
赠书 | 《认知控制》:我们的大脑如何完成任务?