需求:有个web端,然后移动端使用微信小程序。要把微信用户和系统中的用户对应起来
上一篇搞了个钉钉小程序登录:钉钉小程序登录
微信小程序登录,方便用户输入和系统中校验的也就只有手机号了,既能保证用户唯一标识,也能和系统中的用户关联起来。
数据库表:
AbpUserLogins 表是 AbpUsers表和第三方登录的中介
AbpUser表中的PhoneNumber就是这个Providerkey
首先
微信小程序->
wx.login -> 获取到code -> 后端用code 去拿用户openid和session_key ->返回到前台,微信小程序使用getPhoneNumber-》获取到 iv,encryptedData,加上刚才的session_key -> 后端 解密到手机号,用手机号对应到系统中的用户,然后进行必要的校验-》返回token
/// <summary>
/// 微信小程序登录 拿code换 session_key, openid
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
[HttpGet]
public async Task<WeChatToken> GetWeChatToken(ExternalGetTokenModel model)
{
return await _wechatMiniProgramAuthProviderApi.GetWeChatToken(model);
}
/// <summary>
/// 点击获取手机号 -》 session_key,iv, encryptedData
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
[HttpPost]
public async Task<AuthenticateResultModel> WechatAuthenticate([FromBody] ExternalWechatAuthenticateModel model)
{
_currentTenant = _tenantManager.GetTenantByDomainName(model.DomainName);
// 给全局的租户赋值,不然没法访问数据库
_unitOfWorkManager.Current.SetTenantId(_currentTenant.Id);
//string phoneNumber = getPhoneNumber(model);
string phoneNumber = "18253132526";
var user = await _userManager.GetUserByPhoneNumberAsync(phoneNumber);
if (user == null)
{
throw new UserFriendlyException($"手机号为{phoneNumber}的微信用户在系统内不存在!");
}
model.AuthProvider = ProviderName;
model.ProviderKey = phoneNumber;
//model.ProviderKey = user.PhoneNumber;
var loginResult = await _logInManager.LoginAsync(new UserLoginInfo(model.AuthProvider, model.ProviderKey, model.AuthProvider), _currentTenant.TenancyName);
switch (loginResult.Result)
{
case AbpLoginResultType.Success:
{
var accessToken = CreateAccessToken(CreateJwtClaims(loginResult.Identity));
return new AuthenticateResultModel
{
AccessToken = accessToken,
EncryptedAccessToken = GetEncryptedAccessToken(accessToken),
ExpireInSeconds = (int)_configuration.Expiration.TotalSeconds,
UserId = loginResult.User.Id
};
}
case AbpLoginResultType.UnknownExternalLogin:
{
// 理论上不会走这里了
// Try to login again with newly registered user!
loginResult = await _logInManager.LoginAsync(new UserLoginInfo(model.AuthProvider, model.ProviderKey, model.AuthProvider), _currentTenant.TenancyName);
var accessToken = CreateAccessToken(CreateJwtClaims(loginResult.Identity));
if (loginResult.Result != AbpLoginResultType.Success)
{
throw _abpLoginResultTypeHelper.CreateExceptionForFailedLoginAttempt(
loginResult.Result,
model.ProviderKey,
_currentTenant.TenancyName
);
}
return new AuthenticateResultModel
{
AccessToken = accessToken,
EncryptedAccessToken = GetEncryptedAccessToken(accessToken),
ExpireInSeconds = (int)_configuration.Expiration.TotalSeconds,
UserId = loginResult.User.Id
};
}
default:
{
throw _abpLoginResultTypeHelper.CreateExceptionForFailedLoginAttempt(
loginResult.Result,
model.ProviderKey,
_currentTenant.TenancyName
);
}
}
}
/// <summary>
/// 获取用户手机号,session_key, iv, encryptedData
/// </summary>
/// <param name="externalWechatAuthenticateModel"></param>
private string getPhoneNumber(ExternalWechatAuthenticateModel externalWechatAuthenticateModel)
{
try
{
byte[] encryData = Convert.FromBase64String(externalWechatAuthenticateModel.encryptedData);
RijndaelManaged rijndaelCipher = new RijndaelManaged();
rijndaelCipher.Key = Convert.FromBase64String(externalWechatAuthenticateModel.session_key);
rijndaelCipher.IV = Convert.FromBase64String(externalWechatAuthenticateModel.iv);
rijndaelCipher.Mode = CipherMode.CBC;
rijndaelCipher.Padding = PaddingMode.PKCS7;
ICryptoTransform transform = rijndaelCipher.CreateDecryptor();
byte[] plainText = transform.TransformFinalBlock(encryData, 0, encryData.Length);
string result = Encoding.Default.GetString(plainText);
dynamic model = Newtonsoft.Json.Linq.JToken.Parse(result) as dynamic;
string phoneNumber = model.phoneNumber;
//return model.phoneNumber;
if (string.IsNullOrEmpty(phoneNumber))
{
return "";
}
return phoneNumber;
}
catch (Exception ex)
{
throw new UserFriendlyException($"获取用户手机号报错:{ex.Message}");
}
}