|
|
|
@ -3,10 +3,12 @@ using LINGYUN.Abp.Account.Web.Models; |
|
|
|
using Microsoft.AspNetCore.Authentication; |
|
|
|
using Microsoft.AspNetCore.Identity; |
|
|
|
using Microsoft.AspNetCore.Mvc; |
|
|
|
using Microsoft.AspNetCore.Mvc.ModelBinding; |
|
|
|
using Microsoft.Extensions.Logging; |
|
|
|
using Microsoft.Extensions.Options; |
|
|
|
using System; |
|
|
|
using System.Collections.Generic; |
|
|
|
using System.ComponentModel.DataAnnotations; |
|
|
|
using System.Diagnostics; |
|
|
|
using System.Linq; |
|
|
|
using System.Security.Claims; |
|
|
|
@ -15,7 +17,7 @@ using Volo.Abp; |
|
|
|
using Volo.Abp.Account.Settings; |
|
|
|
using Volo.Abp.Account.Web; |
|
|
|
using Volo.Abp.Account.Web.Pages.Account; |
|
|
|
using Volo.Abp.DependencyInjection; |
|
|
|
using Volo.Abp.Auditing; |
|
|
|
using Volo.Abp.Identity; |
|
|
|
using Volo.Abp.Identity.AspNetCore; |
|
|
|
using Volo.Abp.Reflection; |
|
|
|
@ -24,10 +26,10 @@ using Volo.Abp.Settings; |
|
|
|
using Volo.Abp.Validation; |
|
|
|
using static Volo.Abp.Account.Web.Pages.Account.LoginModel; |
|
|
|
using IdentityUser = Volo.Abp.Identity.IdentityUser; |
|
|
|
using IIdentityUserRepository = LINGYUN.Abp.Identity.IIdentityUserRepository; |
|
|
|
|
|
|
|
namespace LINGYUN.Abp.Account.Web.Pages.Account; |
|
|
|
|
|
|
|
//[ExposeServices(typeof(Volo.Abp.Account.Web.Pages.Account.LoginModel))]
|
|
|
|
public class LoginModel : AccountPageModel |
|
|
|
{ |
|
|
|
[HiddenInput] |
|
|
|
@ -38,8 +40,15 @@ public class LoginModel : AccountPageModel |
|
|
|
[BindProperty(SupportsGet = true)] |
|
|
|
public string ReturnUrlHash { get; set; } |
|
|
|
|
|
|
|
[BindProperty] |
|
|
|
public LoginInputModel LoginInput { get; set; } |
|
|
|
[HiddenInput] |
|
|
|
[BindProperty(SupportsGet = true)] |
|
|
|
public LoginType LoginType { get; set; } |
|
|
|
|
|
|
|
[BindProperty(Name = "PasswordLoginInput")] |
|
|
|
public PasswordLoginInputModel PasswordLoginInput { get; set; } |
|
|
|
|
|
|
|
[BindProperty(Name = "PhoneLoginInput")] |
|
|
|
public PhoneLoginInputModel PhoneLoginInput { get; set; } |
|
|
|
|
|
|
|
public bool EnableLocalLogin { get; set; } |
|
|
|
|
|
|
|
@ -50,6 +59,7 @@ public class LoginModel : AccountPageModel |
|
|
|
public IEnumerable<ExternalLoginProviderModel> ExternalProviders { get; set; } |
|
|
|
public IEnumerable<ExternalLoginProviderModel> VisibleExternalProviders => ExternalProviders.Where(x => !x.DisplayName.IsNullOrWhiteSpace()); |
|
|
|
|
|
|
|
protected IIdentityUserRepository UserRepository => LazyServiceProvider.LazyGetRequiredService<IIdentityUserRepository>(); |
|
|
|
|
|
|
|
protected IExternalProviderService ExternalProviderService { get; } |
|
|
|
protected IAuthenticationSchemeProvider SchemeProvider { get; } |
|
|
|
@ -71,7 +81,9 @@ public class LoginModel : AccountPageModel |
|
|
|
|
|
|
|
public virtual async Task<IActionResult> OnGetAsync() |
|
|
|
{ |
|
|
|
LoginInput = new LoginInputModel(); |
|
|
|
LoginType = LoginType.Password; |
|
|
|
PhoneLoginInput = new PhoneLoginInputModel(); |
|
|
|
PasswordLoginInput = new PasswordLoginInputModel(); |
|
|
|
|
|
|
|
ExternalProviders = await GetExternalProviders(); |
|
|
|
|
|
|
|
@ -85,24 +97,30 @@ public class LoginModel : AccountPageModel |
|
|
|
return Page(); |
|
|
|
} |
|
|
|
|
|
|
|
public async virtual Task<IActionResult> OnPostAsync(string action) |
|
|
|
public async virtual Task<IActionResult> OnPostPasswordLogin(string action) |
|
|
|
{ |
|
|
|
await CheckLocalLoginAsync(); |
|
|
|
LoginType = LoginType.Password; |
|
|
|
|
|
|
|
ValidateModel(); |
|
|
|
await CheckLocalLoginAsync(); |
|
|
|
|
|
|
|
ExternalProviders = await GetExternalProviders(); |
|
|
|
|
|
|
|
EnableLocalLogin = await SettingProvider.IsTrueAsync(AccountSettingNames.EnableLocalLogin); |
|
|
|
|
|
|
|
ModelState.RemoveModelErrors(nameof(PhoneLoginInput)); |
|
|
|
if (!TryValidateModel(PasswordLoginInput, nameof(PasswordLoginInput))) |
|
|
|
{ |
|
|
|
return Page(); |
|
|
|
} |
|
|
|
|
|
|
|
await ReplaceEmailToUsernameOfInputIfNeeds(); |
|
|
|
|
|
|
|
await IdentityOptions.SetAsync(); |
|
|
|
|
|
|
|
var result = await SignInManager.PasswordSignInAsync( |
|
|
|
LoginInput.UserNameOrEmailAddress, |
|
|
|
LoginInput.Password, |
|
|
|
LoginInput.RememberMe, |
|
|
|
PasswordLoginInput.UserNameOrEmailAddress, |
|
|
|
PasswordLoginInput.Password, |
|
|
|
PasswordLoginInput.RememberMe, |
|
|
|
true |
|
|
|
); |
|
|
|
|
|
|
|
@ -110,7 +128,7 @@ public class LoginModel : AccountPageModel |
|
|
|
{ |
|
|
|
Identity = IdentitySecurityLogIdentityConsts.Identity, |
|
|
|
Action = result.ToIdentitySecurityLogAction(), |
|
|
|
UserName = LoginInput.UserNameOrEmailAddress |
|
|
|
UserName = PasswordLoginInput.UserNameOrEmailAddress |
|
|
|
}); |
|
|
|
|
|
|
|
if (result.RequiresTwoFactor) |
|
|
|
@ -134,7 +152,7 @@ public class LoginModel : AccountPageModel |
|
|
|
} |
|
|
|
|
|
|
|
//TODO: Find a way of getting user's id from the logged in user and do not query it again like that!
|
|
|
|
var user = await GetIdentityUserAsync(LoginInput.UserNameOrEmailAddress); |
|
|
|
var user = await GetIdentityUserAsync(PasswordLoginInput.UserNameOrEmailAddress); |
|
|
|
|
|
|
|
Debug.Assert(user != null, nameof(user) + " != null"); |
|
|
|
|
|
|
|
@ -144,6 +162,54 @@ public class LoginModel : AccountPageModel |
|
|
|
return await RedirectSafelyAsync(ReturnUrl, ReturnUrlHash); |
|
|
|
} |
|
|
|
|
|
|
|
public async virtual Task<IActionResult> OnPostPhoneNumberLogin(string action) |
|
|
|
{ |
|
|
|
LoginType = LoginType.PhoneNumber; |
|
|
|
|
|
|
|
await CheckLocalLoginAsync(); |
|
|
|
|
|
|
|
ExternalProviders = await GetExternalProviders(); |
|
|
|
|
|
|
|
EnableLocalLogin = await SettingProvider.IsTrueAsync(AccountSettingNames.EnableLocalLogin); |
|
|
|
|
|
|
|
ModelState.RemoveModelErrors(nameof(PasswordLoginInput)); |
|
|
|
if (!TryValidateModel(PhoneLoginInput, nameof(PhoneLoginInput))) |
|
|
|
{ |
|
|
|
return Page(); |
|
|
|
} |
|
|
|
|
|
|
|
var user = await UserRepository.FindByPhoneNumberAsync(PhoneLoginInput.PhoneNumber); |
|
|
|
if (user == null) |
|
|
|
{ |
|
|
|
Logger.LogInformation("the user phone number is not registed!"); |
|
|
|
Alerts.Danger(L["InvalidPhoneNumber"]); |
|
|
|
return Page(); |
|
|
|
} |
|
|
|
|
|
|
|
var result = await UserManager.VerifyTwoFactorTokenAsync(user, TokenOptions.DefaultPhoneProvider, PhoneLoginInput.Code); |
|
|
|
if (!result) |
|
|
|
{ |
|
|
|
Alerts.Danger(L["InvalidVerifyCode"]); |
|
|
|
return Page(); |
|
|
|
} |
|
|
|
|
|
|
|
await SignInManager.SignInAsync( |
|
|
|
user, |
|
|
|
PasswordLoginInput.RememberMe); |
|
|
|
|
|
|
|
await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext() |
|
|
|
{ |
|
|
|
Identity = IdentitySecurityLogIdentityConsts.IdentityTwoFactor, |
|
|
|
Action = IdentitySecurityLogActionConsts.LoginSucceeded, |
|
|
|
UserName = user.UserName |
|
|
|
}); |
|
|
|
|
|
|
|
// Clear the dynamic claims cache.
|
|
|
|
await IdentityDynamicClaimsPrincipalContributorCache.ClearAsync(user.Id, user.TenantId); |
|
|
|
|
|
|
|
return await RedirectSafelyAsync(ReturnUrl, ReturnUrlHash); |
|
|
|
} |
|
|
|
|
|
|
|
public virtual async Task<IActionResult> OnPostExternalLogin(string provider) |
|
|
|
{ |
|
|
|
var redirectUrl = Url.Page("./Login", pageHandler: "ExternalLoginCallback", values: new { ReturnUrl, ReturnUrlHash }); |
|
|
|
@ -267,15 +333,15 @@ public class LoginModel : AccountPageModel |
|
|
|
{ |
|
|
|
returnUrl = ReturnUrl, |
|
|
|
returnUrlHash = ReturnUrlHash, |
|
|
|
rememberMe = LoginInput.RememberMe |
|
|
|
rememberMe = PasswordLoginInput.RememberMe |
|
|
|
})); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
protected virtual async Task<IdentityUser> GetIdentityUserAsync(string userNameOrEmailAddress) |
|
|
|
{ |
|
|
|
return await UserManager.FindByNameAsync(LoginInput.UserNameOrEmailAddress) ?? |
|
|
|
await UserManager.FindByEmailAsync(LoginInput.UserNameOrEmailAddress); |
|
|
|
return await UserManager.FindByNameAsync(PasswordLoginInput.UserNameOrEmailAddress) ?? |
|
|
|
await UserManager.FindByEmailAsync(PasswordLoginInput.UserNameOrEmailAddress); |
|
|
|
} |
|
|
|
|
|
|
|
protected async virtual Task<List<ExternalLoginProviderModel>> GetExternalProviders() |
|
|
|
@ -316,24 +382,24 @@ public class LoginModel : AccountPageModel |
|
|
|
|
|
|
|
protected virtual async Task ReplaceEmailToUsernameOfInputIfNeeds() |
|
|
|
{ |
|
|
|
if (!ValidationHelper.IsValidEmailAddress(LoginInput.UserNameOrEmailAddress)) |
|
|
|
if (!ValidationHelper.IsValidEmailAddress(PasswordLoginInput.UserNameOrEmailAddress)) |
|
|
|
{ |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
var userByUsername = await UserManager.FindByNameAsync(LoginInput.UserNameOrEmailAddress); |
|
|
|
var userByUsername = await UserManager.FindByNameAsync(PasswordLoginInput.UserNameOrEmailAddress); |
|
|
|
if (userByUsername != null) |
|
|
|
{ |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
var userByEmail = await UserManager.FindByEmailAsync(LoginInput.UserNameOrEmailAddress); |
|
|
|
var userByEmail = await UserManager.FindByEmailAsync(PasswordLoginInput.UserNameOrEmailAddress); |
|
|
|
if (userByEmail == null) |
|
|
|
{ |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
LoginInput.UserNameOrEmailAddress = userByEmail.UserName; |
|
|
|
PasswordLoginInput.UserNameOrEmailAddress = userByEmail.UserName; |
|
|
|
} |
|
|
|
|
|
|
|
protected virtual async Task CheckLocalLoginAsync() |
|
|
|
@ -352,8 +418,8 @@ public class LoginModel : AccountPageModel |
|
|
|
|
|
|
|
protected async virtual Task<IActionResult> HandleUserNotAllowed() |
|
|
|
{ |
|
|
|
var notAllowedUser = await GetIdentityUserAsync(LoginInput.UserNameOrEmailAddress); |
|
|
|
if (await UserManager.CheckPasswordAsync(notAllowedUser, LoginInput.Password)) |
|
|
|
var notAllowedUser = await GetIdentityUserAsync(PasswordLoginInput.UserNameOrEmailAddress); |
|
|
|
if (await UserManager.CheckPasswordAsync(notAllowedUser, PasswordLoginInput.Password)) |
|
|
|
{ |
|
|
|
// Óû§±ØÐëÐÞ¸ÄÃÜÂë
|
|
|
|
if (notAllowedUser.ShouldChangePasswordOnNextLogin || await UserManager.ShouldPeriodicallyChangePasswordAsync(notAllowedUser)) |
|
|
|
@ -371,7 +437,7 @@ public class LoginModel : AccountPageModel |
|
|
|
{ |
|
|
|
returnUrl = ReturnUrl, |
|
|
|
returnUrlHash = ReturnUrlHash, |
|
|
|
rememberMe = LoginInput.RememberMe |
|
|
|
rememberMe = PasswordLoginInput.RememberMe |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -385,3 +451,40 @@ public class LoginModel : AccountPageModel |
|
|
|
return Task.FromResult<IActionResult>(Page()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public class PhoneLoginInputModel |
|
|
|
{ |
|
|
|
[Phone] |
|
|
|
[Required] |
|
|
|
[DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxPhoneNumberLength))] |
|
|
|
public string PhoneNumber { get; set; } |
|
|
|
|
|
|
|
[Required] |
|
|
|
[StringLength(6)] |
|
|
|
[Display(Name = "VerifyCode")] |
|
|
|
public string Code { get; set; } |
|
|
|
|
|
|
|
public bool RememberMe { get; set; } |
|
|
|
} |
|
|
|
|
|
|
|
public class PasswordLoginInputModel |
|
|
|
{ |
|
|
|
[Required] |
|
|
|
[DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxEmailLength))] |
|
|
|
public string UserNameOrEmailAddress { get; set; } |
|
|
|
|
|
|
|
[Required] |
|
|
|
[DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxPasswordLength))] |
|
|
|
[DataType(DataType.Password)] |
|
|
|
[DisableAuditing] |
|
|
|
public string Password { get; set; } |
|
|
|
|
|
|
|
public bool RememberMe { get; set; } |
|
|
|
} |
|
|
|
|
|
|
|
public enum LoginType |
|
|
|
{ |
|
|
|
Password = 0, |
|
|
|
PhoneNumber = 1, |
|
|
|
QrCode = 2 |
|
|
|
} |
|
|
|
|