Fix for external logins disappearing after failed login (#7002)
Also adds external logins to register page
This commit is contained in:
parent
368269c883
commit
48a67cfd18
|
|
@ -168,10 +168,11 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal
|
|||
public abstract partial class RegisterModel : Microsoft.AspNetCore.Mvc.RazorPages.PageModel
|
||||
{
|
||||
protected RegisterModel() { }
|
||||
public System.Collections.Generic.IList<Microsoft.AspNetCore.Authentication.AuthenticationScheme> ExternalLogins { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
[Microsoft.AspNetCore.Mvc.BindPropertyAttribute]
|
||||
public Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal.RegisterModel.InputModel Input { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public string ReturnUrl { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public virtual void OnGet(string returnUrl = null) { }
|
||||
public virtual System.Threading.Tasks.Task OnGetAsync(string returnUrl = null) { throw null; }
|
||||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnPostAsync(string returnUrl = null) { throw null; }
|
||||
public partial class InputModel
|
||||
{
|
||||
|
|
@ -580,10 +581,11 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Internal
|
|||
public abstract partial class RegisterModel : Microsoft.AspNetCore.Mvc.RazorPages.PageModel
|
||||
{
|
||||
protected RegisterModel() { }
|
||||
public System.Collections.Generic.IList<Microsoft.AspNetCore.Authentication.AuthenticationScheme> ExternalLogins { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
[Microsoft.AspNetCore.Mvc.BindPropertyAttribute]
|
||||
public Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Internal.RegisterModel.InputModel Input { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public string ReturnUrl { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
public virtual void OnGet(string returnUrl = null) { }
|
||||
public virtual System.Threading.Tasks.Task OnGetAsync(string returnUrl = null) { throw null; }
|
||||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnPostAsync(string returnUrl = null) { throw null; }
|
||||
public partial class InputModel
|
||||
{
|
||||
|
|
|
|||
|
|
@ -124,6 +124,8 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal
|
|||
{
|
||||
returnUrl = returnUrl ?? Url.Content("~/");
|
||||
|
||||
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
|
||||
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
// This doesn't count login failures towards account lockout
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<form asp-route-returnUrl="@Model.ReturnUrl" method="post">
|
||||
<form id="registerForm" asp-route-returnUrl="@Model.ReturnUrl" method="post">
|
||||
<h4>Create a new account.</h4>
|
||||
<hr />
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
|
|
@ -27,9 +27,39 @@
|
|||
<input asp-for="Input.ConfirmPassword" class="form-control" />
|
||||
<span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-default">Register</button>
|
||||
<button id="registerSubmit" type="submit" class="btn btn-default">Register</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-md-6 col-md-offset-2">
|
||||
<section>
|
||||
<h4>Use another service to register.</h4>
|
||||
<hr />
|
||||
@{
|
||||
if ((Model.ExternalLogins?.Count ?? 0) == 0)
|
||||
{
|
||||
<div>
|
||||
<p>
|
||||
There are no external authentication services configured. See <a href="https://go.microsoft.com/fwlink/?LinkID=532715">this article</a>
|
||||
for details on setting up this ASP.NET application to support logging in via external services.
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal">
|
||||
<div>
|
||||
<p>
|
||||
@foreach (var provider in Model.ExternalLogins)
|
||||
{
|
||||
<button type="submit" class="btn btn-default" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
}
|
||||
}
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@section Scripts {
|
||||
|
|
|
|||
|
|
@ -2,10 +2,13 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
|
@ -36,6 +39,12 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal
|
|||
/// </summary>
|
||||
public string ReturnUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public IList<AuthenticationScheme> ExternalLogins { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
|
|
@ -75,7 +84,7 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal
|
|||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public virtual void OnGet(string returnUrl = null) => throw new NotImplementedException();
|
||||
public virtual Task OnGetAsync(string returnUrl = null) => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
|
|
@ -108,14 +117,16 @@ namespace Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal
|
|||
_emailSender = emailSender;
|
||||
}
|
||||
|
||||
public override void OnGet(string returnUrl = null)
|
||||
public override async Task OnGetAsync(string returnUrl = null)
|
||||
{
|
||||
ReturnUrl = returnUrl;
|
||||
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
|
||||
}
|
||||
|
||||
public override async Task<IActionResult> OnPostAsync(string returnUrl = null)
|
||||
{
|
||||
returnUrl = returnUrl ?? Url.Content("~/");
|
||||
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var user = CreateUser();
|
||||
|
|
|
|||
|
|
@ -123,6 +123,8 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Internal
|
|||
{
|
||||
returnUrl = returnUrl ?? Url.Content("~/");
|
||||
|
||||
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
|
||||
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
// This doesn't count login failures towards account lockout
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<form asp-route-returnUrl="@Model.ReturnUrl" method="post">
|
||||
<form id="registerForm" asp-route-returnUrl="@Model.ReturnUrl" method="post">
|
||||
<h4>Create a new account.</h4>
|
||||
<hr />
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
|
|
@ -27,9 +27,39 @@
|
|||
<input asp-for="Input.ConfirmPassword" class="form-control" />
|
||||
<span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Register</button>
|
||||
<button id="registerSubmit" type="submit" class="btn btn-primary">Register</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-md-6 col-md-offset-2">
|
||||
<section>
|
||||
<h4>Use another service to register.</h4>
|
||||
<hr />
|
||||
@{
|
||||
if ((Model.ExternalLogins?.Count ?? 0) == 0)
|
||||
{
|
||||
<div>
|
||||
<p>
|
||||
There are no external authentication services configured. See <a href="https://go.microsoft.com/fwlink/?LinkID=532715">this article</a>
|
||||
for details on setting up this ASP.NET application to support logging in via external services.
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal">
|
||||
<div>
|
||||
<p>
|
||||
@foreach (var provider in Model.ExternalLogins)
|
||||
{
|
||||
<button type="submit" class="btn btn-primary" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
}
|
||||
}
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@section Scripts {
|
||||
|
|
|
|||
|
|
@ -2,10 +2,13 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
|
@ -35,6 +38,12 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Internal
|
|||
/// </summary>
|
||||
public string ReturnUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public IList<AuthenticationScheme> ExternalLogins { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
|
|
@ -74,7 +83,7 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Internal
|
|||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public virtual void OnGet(string returnUrl = null) => throw new NotImplementedException();
|
||||
public virtual Task OnGetAsync(string returnUrl = null) => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
|
||||
|
|
@ -107,14 +116,16 @@ namespace Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Internal
|
|||
_emailSender = emailSender;
|
||||
}
|
||||
|
||||
public override void OnGet(string returnUrl = null)
|
||||
public override async Task OnGetAsync(string returnUrl = null)
|
||||
{
|
||||
ReturnUrl = returnUrl;
|
||||
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
|
||||
}
|
||||
|
||||
public override async Task<IActionResult> OnPostAsync(string returnUrl = null)
|
||||
{
|
||||
returnUrl = returnUrl ?? Url.Content("~/");
|
||||
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var user = CreateUser();
|
||||
|
|
|
|||
|
|
@ -2,10 +2,13 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using IdentitySample.DefaultUI.Data;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
|
@ -38,6 +41,8 @@ namespace IdentitySample.DefaultUI
|
|||
|
||||
public string ReturnUrl { get; set; }
|
||||
|
||||
public IList<AuthenticationScheme> ExternalLogins { get; set; }
|
||||
|
||||
public class InputModel
|
||||
{
|
||||
[Required]
|
||||
|
|
@ -67,14 +72,16 @@ namespace IdentitySample.DefaultUI
|
|||
public int Age { get; set; }
|
||||
}
|
||||
|
||||
public void OnGet(string returnUrl = null)
|
||||
public async Task OnGetAsync(string returnUrl = null)
|
||||
{
|
||||
ReturnUrl = returnUrl;
|
||||
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
|
||||
}
|
||||
|
||||
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
|
||||
{
|
||||
returnUrl = returnUrl ?? Url.Content("~/");
|
||||
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var user = new ApplicationUser {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
|
@ -12,11 +12,29 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account
|
|||
public class Register : DefaultUIPage
|
||||
{
|
||||
private IHtmlFormElement _registerForm;
|
||||
private IHtmlFormElement _externalLoginForm;
|
||||
private readonly IHtmlElement _contosoButton;
|
||||
|
||||
public Register(HttpClient client, IHtmlDocument register, DefaultUIContext context)
|
||||
: base(client, register, context)
|
||||
{
|
||||
_registerForm = HtmlAssert.HasForm(register);
|
||||
_registerForm = HtmlAssert.HasForm("#registerForm", register);
|
||||
if (context.ContosoLoginEnabled)
|
||||
{
|
||||
_externalLoginForm = HtmlAssert.HasForm("#external-account", register);
|
||||
_contosoButton = HtmlAssert.HasElement("button[value=Contoso]", register);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Contoso.Login> ClickLoginWithContosoLinkAsync()
|
||||
{
|
||||
var externalFormResponse = await Client.SendAsync(_externalLoginForm, _contosoButton);
|
||||
var goToContosoLogin = ResponseAssert.IsRedirect(externalFormResponse);
|
||||
var contosoLoginResponse = await Client.GetAsync(goToContosoLogin);
|
||||
|
||||
var contosoLogin = await ResponseAssert.IsHtmlDocumentAsync(contosoLoginResponse);
|
||||
|
||||
return new Contoso.Login(Client, contosoLogin, Context);
|
||||
}
|
||||
|
||||
public async Task<Index> SubmitRegisterFormForValidUserAsync(string userName, string password)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
|
@ -56,7 +56,7 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanRegisterWithASocialLoginProvider()
|
||||
public async Task CanRegisterWithASocialLoginProviderFromLogin()
|
||||
{
|
||||
// Arrange
|
||||
void ConfigureTestServices(IServiceCollection services) =>
|
||||
|
|
@ -75,6 +75,26 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
await UserStories.RegisterNewUserWithSocialLoginAsync(client, userName, email);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanRegisterWithASocialLoginProviderFromRegister()
|
||||
{
|
||||
// Arrange
|
||||
void ConfigureTestServices(IServiceCollection services) =>
|
||||
services
|
||||
.SetupTestThirdPartyLogin();
|
||||
|
||||
var client = ServerFactory
|
||||
.WithWebHostBuilder(whb => whb.ConfigureServices(ConfigureTestServices))
|
||||
.CreateClient();
|
||||
|
||||
var guid = Guid.NewGuid();
|
||||
var userName = $"{guid}";
|
||||
var email = $"{guid}@example.com";
|
||||
|
||||
// Act & Assert
|
||||
await UserStories.RegisterNewUserWithSocialLoginAsyncViaRegisterPage(client, userName, email);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanRegisterWithASocialLoginProvider_WithGlobalAuthorizeFilter()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
|
@ -55,6 +55,7 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
return await login.LockoutUserAsync(userName, password);
|
||||
}
|
||||
|
||||
// This is via login page
|
||||
internal static async Task<Index> RegisterNewUserWithSocialLoginAsync(HttpClient client, string userName, string email)
|
||||
{
|
||||
var index = await Index.CreateAsync(client, new DefaultUIContext().WithSocialLoginEnabled());
|
||||
|
|
@ -68,6 +69,19 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
return await externalLogin.SendEmailAsync(email);
|
||||
}
|
||||
|
||||
internal static async Task<Index> RegisterNewUserWithSocialLoginAsyncViaRegisterPage(HttpClient client, string userName, string email)
|
||||
{
|
||||
var index = await Index.CreateAsync(client, new DefaultUIContext().WithSocialLoginEnabled());
|
||||
|
||||
var register = await index.ClickRegisterLinkAsync();
|
||||
|
||||
var contosoLogin = await register.ClickLoginWithContosoLinkAsync();
|
||||
|
||||
var externalLogin = await contosoLogin.SendNewUserNameAsync(userName);
|
||||
|
||||
return await externalLogin.SendEmailAsync(email);
|
||||
}
|
||||
|
||||
internal static async Task<Account.Manage.Index> SendEmailConfirmationLinkAsync(Index index)
|
||||
{
|
||||
var manage = await index.ClickManageLinkAsync();
|
||||
|
|
|
|||
Loading…
Reference in New Issue