committed by
GitHub
2 changed files with 344 additions and 0 deletions
@ -0,0 +1,53 @@ |
|||||
|
@page |
||||
|
@using Microsoft.AspNetCore.Mvc.Localization |
||||
|
@using Volo.Abp.Account.Localization |
||||
|
@model LINGYUN.Abp.Account.Web.Pages.Account.RegisterModel |
||||
|
@inject IHtmlLocalizer<AccountResource> L |
||||
|
|
||||
|
<div class="card mt-3 shadow-sm rounded"> |
||||
|
<div class="card-body p-5"> |
||||
|
<h4>@L["Register"]</h4> |
||||
|
<strong> |
||||
|
@L["AlreadyRegistered"] |
||||
|
<a href="@Url.Page("./Login", new {returnUrl = Model.ReturnUrl, returnUrlHash = Model.ReturnUrlHash})" class="text-decoration-none">@L["Login"]</a> |
||||
|
</strong> |
||||
|
<form method="post" class="mt-4"> |
||||
|
@if (Model.EnableLocalRegister || Model.IsExternalLogin) |
||||
|
{ |
||||
|
<abp-input asp-for="Input.UserName" auto-focus="true" /> |
||||
|
} |
||||
|
|
||||
|
@if (Model.EnableLocalRegister || Model.IsExternalLogin) |
||||
|
{ |
||||
|
<abp-input asp-for="Input.EmailAddress" /> |
||||
|
} |
||||
|
|
||||
|
@if (!Model.IsExternalLogin && Model.EnableLocalRegister) |
||||
|
{ |
||||
|
<abp-input asp-for="Input.Password" /> |
||||
|
} |
||||
|
|
||||
|
@if (Model.EnableLocalRegister || Model.IsExternalLogin) |
||||
|
{ |
||||
|
<div class="d-grid gap-2"> |
||||
|
<abp-button button-type="Primary" type="submit" class="btn-lg mt-4">@L["Register"]</abp-button> |
||||
|
</div> |
||||
|
} |
||||
|
|
||||
|
</form> |
||||
|
|
||||
|
@if (!Model.IsExternalLogin && Model.VisibleExternalProviders.Any()) |
||||
|
{ |
||||
|
<div class="mt-2"> |
||||
|
<h5>@L["OrRegisterWith"]</h5> |
||||
|
<form asp-page="./Login" asp-page-handler="ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" asp-route-returnUrlHash="@Model.ReturnUrlHash" method="post"> |
||||
|
@foreach (var provider in Model.VisibleExternalProviders) |
||||
|
{ |
||||
|
@await Component.InvokeAsync(provider.ComponentType, provider); |
||||
|
} |
||||
|
</form> |
||||
|
</div> |
||||
|
} |
||||
|
|
||||
|
</div> |
||||
|
</div> |
||||
@ -0,0 +1,291 @@ |
|||||
|
using LINGYUN.Abp.Account.Web.ExternalProviders; |
||||
|
using LINGYUN.Abp.Account.Web.Models; |
||||
|
using Microsoft.AspNetCore.Authentication; |
||||
|
using Microsoft.AspNetCore.Identity; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
using System.Linq; |
||||
|
using System.Security.Claims; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Account; |
||||
|
using Volo.Abp.Account.Settings; |
||||
|
using Volo.Abp.Account.Web; |
||||
|
using Volo.Abp.Account.Web.Pages.Account; |
||||
|
using Volo.Abp.Auditing; |
||||
|
using Volo.Abp.Identity; |
||||
|
using Volo.Abp.Reflection; |
||||
|
using Volo.Abp.Security.Claims; |
||||
|
using Volo.Abp.Settings; |
||||
|
using Volo.Abp.Validation; |
||||
|
using IAbpAccountAppService = Volo.Abp.Account.IAccountAppService; |
||||
|
using IdentityUser = Volo.Abp.Identity.IdentityUser; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Account.Web.Pages.Account; |
||||
|
|
||||
|
public class RegisterModel : AccountPageModel |
||||
|
{ |
||||
|
|
||||
|
[BindProperty(SupportsGet = true)] |
||||
|
public string ReturnUrl { get; set; } |
||||
|
|
||||
|
[BindProperty(SupportsGet = true)] |
||||
|
public string ReturnUrlHash { get; set; } |
||||
|
|
||||
|
[BindProperty] |
||||
|
public PostInput Input { get; set; } |
||||
|
|
||||
|
[BindProperty(SupportsGet = true)] |
||||
|
public bool IsExternalLogin { get; set; } |
||||
|
|
||||
|
[BindProperty(SupportsGet = true)] |
||||
|
public string ExternalLoginAuthSchema { get; set; } |
||||
|
|
||||
|
public IEnumerable<ExternalLoginProviderModel> ExternalProviders { get; set; } |
||||
|
public IEnumerable<ExternalLoginProviderModel> VisibleExternalProviders => ExternalProviders.Where(x => !string.IsNullOrWhiteSpace(x.DisplayName)); |
||||
|
public bool EnableLocalRegister { get; set; } |
||||
|
public bool IsExternalLoginOnly => EnableLocalRegister == false && ExternalProviders?.Count() == 1; |
||||
|
public string ExternalLoginScheme => IsExternalLoginOnly ? ExternalProviders?.SingleOrDefault()?.AuthenticationScheme : null; |
||||
|
|
||||
|
protected IExternalProviderService ExternalProviderService { get; } |
||||
|
protected IAuthenticationSchemeProvider SchemeProvider { get; } |
||||
|
|
||||
|
protected AbpAccountOptions AccountOptions { get; } |
||||
|
protected IdentityDynamicClaimsPrincipalContributorCache IdentityDynamicClaimsPrincipalContributorCache { get; } |
||||
|
|
||||
|
public RegisterModel( |
||||
|
IExternalProviderService externalProviderService, |
||||
|
IAbpAccountAppService accountAppService, |
||||
|
IAuthenticationSchemeProvider schemeProvider, |
||||
|
IOptions<AbpAccountOptions> accountOptions, |
||||
|
IdentityDynamicClaimsPrincipalContributorCache identityDynamicClaimsPrincipalContributorCache) |
||||
|
{ |
||||
|
ExternalProviderService = externalProviderService; |
||||
|
SchemeProvider = schemeProvider; |
||||
|
IdentityDynamicClaimsPrincipalContributorCache = identityDynamicClaimsPrincipalContributorCache; |
||||
|
AccountAppService = accountAppService; |
||||
|
AccountOptions = accountOptions.Value; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<IActionResult> OnGetAsync() |
||||
|
{ |
||||
|
ExternalProviders = await GetExternalProviders(); |
||||
|
|
||||
|
if (!await CheckSelfRegistrationAsync()) |
||||
|
{ |
||||
|
if (IsExternalLoginOnly) |
||||
|
{ |
||||
|
return await OnPostExternalLogin(ExternalLoginScheme); |
||||
|
} |
||||
|
|
||||
|
Alerts.Warning(L["SelfRegistrationDisabledMessage"]); |
||||
|
} |
||||
|
|
||||
|
await TrySetEmailAsync(); |
||||
|
|
||||
|
return Page(); |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task TrySetEmailAsync() |
||||
|
{ |
||||
|
if (IsExternalLogin) |
||||
|
{ |
||||
|
var externalLoginInfo = await SignInManager.GetExternalLoginInfoAsync(); |
||||
|
if (externalLoginInfo == null) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (!externalLoginInfo.Principal.Identities.Any()) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
var identity = externalLoginInfo.Principal.Identities.First(); |
||||
|
var emailClaim = identity.FindFirst(AbpClaimTypes.Email) ?? identity.FindFirst(ClaimTypes.Email); |
||||
|
|
||||
|
if (emailClaim == null) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
var userName = await UserManager.GetUserNameFromEmailAsync(emailClaim.Value); |
||||
|
Input = new PostInput { UserName = userName, EmailAddress = emailClaim.Value }; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<IActionResult> OnPostAsync() |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
ExternalProviders = await GetExternalProviders(); |
||||
|
|
||||
|
if (!await CheckSelfRegistrationAsync()) |
||||
|
{ |
||||
|
throw new UserFriendlyException(L["SelfRegistrationDisabledMessage"]); |
||||
|
} |
||||
|
|
||||
|
if (IsExternalLogin) |
||||
|
{ |
||||
|
var externalLoginInfo = await SignInManager.GetExternalLoginInfoAsync(); |
||||
|
if (externalLoginInfo == null) |
||||
|
{ |
||||
|
Logger.LogWarning("External login info is not available"); |
||||
|
return RedirectToPage("./Login"); |
||||
|
} |
||||
|
if (Input.UserName.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
Input.UserName = await UserManager.GetUserNameFromEmailAsync(Input.EmailAddress); |
||||
|
} |
||||
|
await RegisterExternalUserAsync(externalLoginInfo, Input.UserName, Input.EmailAddress); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
await RegisterLocalUserAsync(); |
||||
|
} |
||||
|
|
||||
|
return Redirect(ReturnUrl ?? "~/"); //TODO: How to ensure safety? IdentityServer requires it however it should be checked somehow!
|
||||
|
} |
||||
|
catch (BusinessException e) |
||||
|
{ |
||||
|
Alerts.Danger(GetLocalizeExceptionMessage(e)); |
||||
|
return Page(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task RegisterLocalUserAsync() |
||||
|
{ |
||||
|
ValidateModel(); |
||||
|
|
||||
|
var userDto = await AccountAppService.RegisterAsync( |
||||
|
new RegisterDto |
||||
|
{ |
||||
|
AppName = "MVC", |
||||
|
EmailAddress = Input.EmailAddress, |
||||
|
Password = Input.Password, |
||||
|
UserName = Input.UserName |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
var user = await UserManager.GetByIdAsync(userDto.Id); |
||||
|
await SignInManager.SignInAsync(user, isPersistent: true); |
||||
|
|
||||
|
// Clear the dynamic claims cache.
|
||||
|
await IdentityDynamicClaimsPrincipalContributorCache.ClearAsync(user.Id, user.TenantId); |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task RegisterExternalUserAsync(ExternalLoginInfo externalLoginInfo, string userName, string emailAddress) |
||||
|
{ |
||||
|
await IdentityOptions.SetAsync(); |
||||
|
|
||||
|
var user = new IdentityUser(GuidGenerator.Create(), userName, emailAddress, CurrentTenant.Id); |
||||
|
|
||||
|
(await UserManager.CreateAsync(user)).CheckErrors(); |
||||
|
(await UserManager.AddDefaultRolesAsync(user)).CheckErrors(); |
||||
|
|
||||
|
var userLoginAlreadyExists = user.Logins.Any(x => |
||||
|
x.TenantId == user.TenantId && |
||||
|
x.LoginProvider == externalLoginInfo.LoginProvider && |
||||
|
x.ProviderKey == externalLoginInfo.ProviderKey); |
||||
|
|
||||
|
if (!userLoginAlreadyExists) |
||||
|
{ |
||||
|
(await UserManager.AddLoginAsync(user, new UserLoginInfo( |
||||
|
externalLoginInfo.LoginProvider, |
||||
|
externalLoginInfo.ProviderKey, |
||||
|
externalLoginInfo.ProviderDisplayName |
||||
|
))).CheckErrors(); |
||||
|
} |
||||
|
|
||||
|
await SignInManager.SignInAsync(user, isPersistent: true, ExternalLoginAuthSchema); |
||||
|
|
||||
|
// Clear the dynamic claims cache.
|
||||
|
await IdentityDynamicClaimsPrincipalContributorCache.ClearAsync(user.Id, user.TenantId); |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<bool> CheckSelfRegistrationAsync() |
||||
|
{ |
||||
|
EnableLocalRegister = await SettingProvider.IsTrueAsync(AccountSettingNames.EnableLocalLogin) && |
||||
|
await SettingProvider.IsTrueAsync(AccountSettingNames.IsSelfRegistrationEnabled); |
||||
|
|
||||
|
if (IsExternalLogin) |
||||
|
{ |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
if (!EnableLocalRegister) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
protected async virtual Task<List<ExternalLoginProviderModel>> GetExternalProviders() |
||||
|
{ |
||||
|
var schemes = await SchemeProvider.GetAllSchemesAsync(); |
||||
|
var externalProviders = await ExternalProviderService.GetAllAsync(); |
||||
|
|
||||
|
var externalProviderModels = new List<ExternalLoginProviderModel>(); |
||||
|
foreach (var scheme in schemes) |
||||
|
{ |
||||
|
if (TryGetExternalLoginProvider(scheme, externalProviders, out var externalLoginProvider) || |
||||
|
scheme.Name.Equals(AccountOptions.WindowsAuthenticationSchemeName, StringComparison.OrdinalIgnoreCase)) |
||||
|
{ |
||||
|
externalProviderModels.Add(new ExternalLoginProviderModel |
||||
|
{ |
||||
|
Name = externalLoginProvider.Name, |
||||
|
AuthenticationScheme = scheme.Name, |
||||
|
DisplayName = externalLoginProvider.DisplayName, |
||||
|
ComponentType = externalLoginProvider.ComponentType, |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return externalProviderModels; |
||||
|
} |
||||
|
|
||||
|
protected virtual bool TryGetExternalLoginProvider(AuthenticationScheme scheme, List<ExternalLoginProviderModel> externalProviders, out ExternalLoginProviderModel externalLoginProvider) |
||||
|
{ |
||||
|
if (ReflectionHelper.IsAssignableToGenericType(scheme.HandlerType, typeof(RemoteAuthenticationHandler<>))) |
||||
|
{ |
||||
|
externalLoginProvider = externalProviders.FirstOrDefault(x => x.Name == scheme.Name); |
||||
|
return externalLoginProvider != null; |
||||
|
} |
||||
|
|
||||
|
externalLoginProvider = null; |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<IActionResult> OnPostExternalLogin(string provider) |
||||
|
{ |
||||
|
var redirectUrl = Url.Page("./Login", pageHandler: "ExternalLoginCallback", values: new { ReturnUrl, ReturnUrlHash }); |
||||
|
var properties = SignInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl); |
||||
|
properties.Items["scheme"] = provider; |
||||
|
|
||||
|
return await Task.FromResult(Challenge(properties, provider)); |
||||
|
} |
||||
|
|
||||
|
public class PostInput |
||||
|
{ |
||||
|
[Required] |
||||
|
[DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxUserNameLength))] |
||||
|
public string UserName { get; set; } |
||||
|
|
||||
|
[Required] |
||||
|
[EmailAddress] |
||||
|
[DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxEmailLength))] |
||||
|
public string EmailAddress { get; set; } |
||||
|
|
||||
|
[Required] |
||||
|
[DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxPasswordLength))] |
||||
|
[DataType(DataType.Password)] |
||||
|
[DisableAuditing] |
||||
|
public string Password { get; set; } |
||||
|
} |
||||
|
} |
||||
|
|
||||
Loading…
Reference in new issue