Add an end to end test for login in with a social provider.
This commit is contained in:
parent
5c105e6506
commit
d1aa7d527b
|
|
@ -234,7 +234,6 @@ Global
|
|||
{D5FB2E24-4C71-430C-A289-59C8D59164B0}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{D5FB2E24-4C71-430C-A289-59C8D59164B0}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{D5FB2E24-4C71-430C-A289-59C8D59164B0}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{D5FB2E24-4C71-430C-A289-59C8D59164B0}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{D5FB2E24-4C71-430C-A289-59C8D59164B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D5FB2E24-4C71-430C-A289-59C8D59164B0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D5FB2E24-4C71-430C-A289-59C8D59164B0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
|
|
@ -282,7 +281,6 @@ Global
|
|||
{EA424B4D-0BE1-49AC-A106-CC6CC808A104}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{EA424B4D-0BE1-49AC-A106-CC6CC808A104}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{EA424B4D-0BE1-49AC-A106-CC6CC808A104}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{EA424B4D-0BE1-49AC-A106-CC6CC808A104}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{EA424B4D-0BE1-49AC-A106-CC6CC808A104}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EA424B4D-0BE1-49AC-A106-CC6CC808A104}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{EA424B4D-0BE1-49AC-A106-CC6CC808A104}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<section>
|
||||
<form method="post">
|
||||
<form id="account" method="post">
|
||||
<h4>Use a local account to log in.</h4>
|
||||
<hr />
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
|
|
@ -61,7 +61,7 @@
|
|||
}
|
||||
else
|
||||
{
|
||||
<form asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal">
|
||||
<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)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
// 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;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using AngleSharp.Dom.Html;
|
||||
using Xunit;
|
||||
|
|
@ -16,7 +14,27 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
public static Task<HttpResponseMessage> SendAsync(
|
||||
this HttpClient client,
|
||||
IHtmlFormElement form,
|
||||
IEnumerable<KeyValuePair<string,string>> formValues)
|
||||
IHtmlElement submitButton)
|
||||
{
|
||||
return client.SendAsync(form, submitButton, new Dictionary<string, string>());
|
||||
}
|
||||
|
||||
public static Task<HttpResponseMessage> SendAsync(
|
||||
this HttpClient client,
|
||||
IHtmlFormElement form,
|
||||
IEnumerable<KeyValuePair<string, string>> formValues)
|
||||
{
|
||||
var submitElement = Assert.Single(form.QuerySelectorAll("[type=submit]"));
|
||||
var submitButton = Assert.IsAssignableFrom<IHtmlElement>(submitElement);
|
||||
|
||||
return client.SendAsync(form, submitButton, formValues);
|
||||
}
|
||||
|
||||
public static Task<HttpResponseMessage> SendAsync(
|
||||
this HttpClient client,
|
||||
IHtmlFormElement form,
|
||||
IHtmlElement submitButton,
|
||||
IEnumerable<KeyValuePair<string, string>> formValues)
|
||||
{
|
||||
foreach (var kvp in formValues)
|
||||
{
|
||||
|
|
@ -24,9 +42,6 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
element.Value = kvp.Value;
|
||||
}
|
||||
|
||||
var submitElement = Assert.Single(form.QuerySelectorAll("[type=submit]"));
|
||||
var submitButton = Assert.IsAssignableFrom<IHtmlElement>(submitElement);
|
||||
|
||||
var submit = form.GetSubmission(submitButton);
|
||||
var submision = new HttpRequestMessage(new HttpMethod(submit.Method.ToString()), submit.Target)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
||||
{
|
||||
public class DefaultUIContext : HtmlPageContext
|
||||
{
|
||||
public DefaultUIContext()
|
||||
{
|
||||
}
|
||||
|
||||
public DefaultUIContext(DefaultUIContext currentContext)
|
||||
: base(currentContext)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public DefaultUIContext WithAuthenticatedUser() =>
|
||||
new DefaultUIContext(this) { UserAuthenticated = true };
|
||||
|
||||
public DefaultUIContext WithSocialLoginEnabled() =>
|
||||
new DefaultUIContext(this) { ContosoLoginEnabled = true };
|
||||
|
||||
public DefaultUIContext WithExistingUser() =>
|
||||
new DefaultUIContext(this) { ExistingUser = true };
|
||||
|
||||
public string AuthenticatorKey
|
||||
{
|
||||
get => GetValue<string>(nameof(AuthenticatorKey));
|
||||
set => SetValue(nameof(AuthenticatorKey), value);
|
||||
}
|
||||
|
||||
public string[] RecoveryCodes
|
||||
{
|
||||
get => GetValue<string[]>(nameof(RecoveryCodes));
|
||||
set => SetValue(nameof(RecoveryCodes), value);
|
||||
}
|
||||
|
||||
public bool TwoFactorEnabled
|
||||
{
|
||||
get => GetValue<bool>(nameof(TwoFactorEnabled));
|
||||
set => SetValue(nameof(TwoFactorEnabled), value);
|
||||
}
|
||||
public bool ContosoLoginEnabled
|
||||
{
|
||||
get => GetValue<bool>(nameof(ContosoLoginEnabled));
|
||||
set => SetValue(nameof(ContosoLoginEnabled), value);
|
||||
}
|
||||
|
||||
public bool UserAuthenticated
|
||||
{
|
||||
get => GetValue<bool>(nameof(UserAuthenticated));
|
||||
set => SetValue(nameof(UserAuthenticated), value);
|
||||
}
|
||||
public bool ExistingUser
|
||||
{
|
||||
get => GetValue<bool>(nameof(ExistingUser));
|
||||
set => SetValue(nameof(ExistingUser), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using AngleSharp.Dom.Html;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
||||
{
|
||||
public class DefaultUIPage : HtmlPage<DefaultUIContext>
|
||||
{
|
||||
public DefaultUIPage(HttpClient client, IHtmlDocument document, DefaultUIContext context)
|
||||
: base(client, document, context)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
// 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 Identity.DefaultUI.WebSite;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
|
@ -9,12 +10,13 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
{
|
||||
public static class FunctionalTestsServiceCollectionExtensions
|
||||
{
|
||||
public static IServiceCollection SetupTestDatabase(this IServiceCollection services, string databaseName)
|
||||
{
|
||||
public static IServiceCollection SetupTestDatabase(this IServiceCollection services, string databaseName) =>
|
||||
services.AddDbContext<IdentityDbContext>(options =>
|
||||
options.UseInMemoryDatabase(databaseName, memoryOptions => { }));
|
||||
|
||||
return services;
|
||||
}
|
||||
public static IServiceCollection SetupTestThirdPartyLogin(this IServiceCollection services) =>
|
||||
services.AddAuthentication()
|
||||
.AddContosoAuthentication(o => o.SignInScheme = IdentityConstants.ExternalScheme)
|
||||
.Services;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ using AngleSharp.Dom.Html;
|
|||
|
||||
namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
||||
{
|
||||
public class HtmlPage
|
||||
public class HtmlPage<TApplicationContext>
|
||||
{
|
||||
public HtmlPage(HttpClient client, IHtmlDocument document, HtmlPageContext context)
|
||||
public HtmlPage(HttpClient client, IHtmlDocument document, TApplicationContext context)
|
||||
{
|
||||
Client = client;
|
||||
Document = document;
|
||||
|
|
@ -17,6 +17,6 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
|
||||
public HttpClient Client { get; }
|
||||
public IHtmlDocument Document { get; }
|
||||
public HtmlPageContext Context { get; }
|
||||
public TApplicationContext Context { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,13 +7,26 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
{
|
||||
public class HtmlPageContext
|
||||
{
|
||||
private readonly IDictionary<string, string> _properties =
|
||||
new Dictionary<string, string>();
|
||||
private readonly IDictionary<string, object> _properties;
|
||||
|
||||
public string this[string key]
|
||||
protected HtmlPageContext()
|
||||
: this(new Dictionary<string, object>())
|
||||
{
|
||||
get => _properties[key];
|
||||
set => _properties[key] = value;
|
||||
}
|
||||
|
||||
protected HtmlPageContext(HtmlPageContext currentContext)
|
||||
: this(new Dictionary<string,object>(currentContext._properties))
|
||||
{
|
||||
}
|
||||
|
||||
private HtmlPageContext(IDictionary<string, object> properties)
|
||||
{
|
||||
_properties = properties;
|
||||
}
|
||||
|
||||
protected TValue GetValue<TValue>(string key) =>
|
||||
_properties.TryGetValue(key, out var rawValue) ? (TValue)rawValue : default;
|
||||
protected void SetValue(string key, object value) =>
|
||||
_properties[key] = value;
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,6 @@ using System;
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using AngleSharp.Dom.Html;
|
||||
using Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage;
|
||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Xunit;
|
||||
|
|
@ -45,9 +44,9 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
var password = $"!Test.Password1$";
|
||||
|
||||
var loggedIn = await UserStories.RegisterNewUserAsync(client, userName, password);
|
||||
var showRecoveryCodes = await UserStories.EnableTwoFactorAuthentication(loggedIn, twoFactorEnabled: false);
|
||||
var showRecoveryCodes = await UserStories.EnableTwoFactorAuthentication(loggedIn);
|
||||
|
||||
var twoFactorKey = showRecoveryCodes.Context[EnableAuthenticator.AuthenticatorKey];
|
||||
var twoFactorKey = showRecoveryCodes.Context.AuthenticatorKey;
|
||||
|
||||
// Act & Assert
|
||||
// Use a new client to simulate a new browser session.
|
||||
|
|
@ -66,11 +65,9 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
var password = $"!Test.Password1$";
|
||||
|
||||
var loggedIn = await UserStories.RegisterNewUserAsync(client, userName, password);
|
||||
var showRecoveryCodes = await UserStories.EnableTwoFactorAuthentication(loggedIn, twoFactorEnabled: false);
|
||||
var showRecoveryCodes = await UserStories.EnableTwoFactorAuthentication(loggedIn);
|
||||
|
||||
var recoveryCode = showRecoveryCodes.Context[ShowRecoveryCodes.RecoveryCodes]
|
||||
.Split(' ')
|
||||
.First();
|
||||
var recoveryCode = showRecoveryCodes.Context.RecoveryCodes.First();
|
||||
|
||||
// Act & Assert
|
||||
// Use a new client to simulate a new browser session.
|
||||
|
|
@ -131,6 +128,24 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
|
||||
await UserStories.LoginExistingUserAsync(newClient, userName, password);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanLoginWithASocialLoginProvider()
|
||||
{
|
||||
// Arrange
|
||||
var server = ServerFactory.CreateServer(builder =>
|
||||
builder.ConfigureServices(services => services.SetupTestThirdPartyLogin()));
|
||||
var client = ServerFactory.CreateDefaultClient(server);
|
||||
var newClient = ServerFactory.CreateDefaultClient(server);
|
||||
|
||||
var guid = Guid.NewGuid();
|
||||
var userName = $"{guid}";
|
||||
var email = $"{guid}@example.com";
|
||||
|
||||
// Act & Assert
|
||||
await UserStories.RegisterNewUserWithSocialLoginAsync(client, userName, email);
|
||||
await UserStories.LoginWithSocialLoginAsync(newClient, userName);
|
||||
}
|
||||
}
|
||||
|
||||
class TestEmailSender : IEmailSender
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
var index = await UserStories.RegisterNewUserAsync(client, userName, password);
|
||||
|
||||
// Act & Assert
|
||||
await UserStories.EnableTwoFactorAuthentication(index, twoFactorEnabled: false);
|
||||
await UserStories.EnableTwoFactorAuthentication(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using AngleSharp.Dom.Html;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.FunctionalTests.Pages.Account
|
||||
{
|
||||
public class ExternalLogin : DefaultUIPage
|
||||
{
|
||||
private readonly IHtmlFormElement _emailForm;
|
||||
|
||||
public ExternalLogin(
|
||||
HttpClient client,
|
||||
IHtmlDocument externalLogin,
|
||||
DefaultUIContext context)
|
||||
: base(client, externalLogin, context)
|
||||
{
|
||||
_emailForm = HtmlAssert.HasForm(Document);
|
||||
}
|
||||
|
||||
public async Task<Index> SendEmailAsync(string email)
|
||||
{
|
||||
var response = await Client.SendAsync(_emailForm, new Dictionary<string, string>
|
||||
{
|
||||
["Input_Email"] = email
|
||||
});
|
||||
var goToIndex = ResponseAssert.IsRedirect(response);
|
||||
var indexResponse = await Client.GetAsync(goToIndex);
|
||||
var index = await ResponseAssert.IsHtmlDocumentAsync(indexResponse);
|
||||
|
||||
return new Index(Client, index, Context.WithAuthenticatedUser());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -9,14 +9,35 @@ using Xunit;
|
|||
|
||||
namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account
|
||||
{
|
||||
public class Login : HtmlPage
|
||||
public class Login : DefaultUIPage
|
||||
{
|
||||
private readonly IHtmlFormElement _loginForm;
|
||||
private readonly IHtmlFormElement _externalLoginForm;
|
||||
private readonly IHtmlElement _contosoButton;
|
||||
|
||||
public Login(HttpClient client, IHtmlDocument login, HtmlPageContext context)
|
||||
public Login(
|
||||
HttpClient client,
|
||||
IHtmlDocument login,
|
||||
DefaultUIContext context)
|
||||
: base(client, login, context)
|
||||
{
|
||||
_loginForm = HtmlAssert.HasForm(login);
|
||||
_loginForm = HtmlAssert.HasForm("#account", login);
|
||||
if (Context.ContosoLoginEnabled)
|
||||
{
|
||||
_externalLoginForm = HtmlAssert.HasForm("#external-account", login);
|
||||
_contosoButton = HtmlAssert.HasElement("button[value=Contoso]", login);
|
||||
}
|
||||
}
|
||||
|
||||
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> LoginValidUserAsync(string userName, string password)
|
||||
|
|
@ -27,7 +48,10 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account
|
|||
Assert.Equal(Index.Path, loggedInLocation.ToString());
|
||||
var indexResponse = await Client.GetAsync(loggedInLocation);
|
||||
var index = await ResponseAssert.IsHtmlDocumentAsync(indexResponse);
|
||||
return new Index(Client, index, Context, authenticated: true);
|
||||
return new Index(
|
||||
Client,
|
||||
index,
|
||||
Context.WithAuthenticatedUser());
|
||||
}
|
||||
|
||||
private async Task<HttpResponseMessage> SendLoginForm(string userName, string password)
|
||||
|
|
|
|||
|
|
@ -10,14 +10,14 @@ using Xunit;
|
|||
|
||||
namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account
|
||||
{
|
||||
public class LoginWith2fa : HtmlPage
|
||||
public class LoginWith2fa : DefaultUIPage
|
||||
{
|
||||
public const string Path = "/Identity/Account/LoginWith2fa";
|
||||
|
||||
private readonly IHtmlFormElement _twoFactorForm;
|
||||
private readonly IHtmlAnchorElement _loginWithRecoveryCodeLink;
|
||||
|
||||
public LoginWith2fa(HttpClient client, IHtmlDocument loginWithTwoFactor, HtmlPageContext context)
|
||||
public LoginWith2fa(HttpClient client, IHtmlDocument loginWithTwoFactor, DefaultUIContext context)
|
||||
: base(client, loginWithTwoFactor, context)
|
||||
{
|
||||
_twoFactorForm = HtmlAssert.HasForm(loginWithTwoFactor);
|
||||
|
|
@ -38,7 +38,7 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account
|
|||
var indexResponse = await Client.GetAsync(goToIndex);
|
||||
var index = await ResponseAssert.IsHtmlDocumentAsync(indexResponse);
|
||||
|
||||
return new Index(Client, index, Context, true);
|
||||
return new Index(Client, index, Context.WithAuthenticatedUser());
|
||||
}
|
||||
|
||||
internal async Task<LoginWithRecoveryCode> ClickRecoveryCodeLinkAsync()
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@ using AngleSharp.Dom.Html;
|
|||
|
||||
namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account
|
||||
{
|
||||
public class LoginWithRecoveryCode : HtmlPage
|
||||
public class LoginWithRecoveryCode : DefaultUIPage
|
||||
{
|
||||
private readonly IHtmlFormElement _loginWithRecoveryCodeForm;
|
||||
|
||||
public LoginWithRecoveryCode(HttpClient client, IHtmlDocument loginWithRecoveryCode, HtmlPageContext context)
|
||||
public LoginWithRecoveryCode(HttpClient client, IHtmlDocument loginWithRecoveryCode, DefaultUIContext context)
|
||||
: base(client, loginWithRecoveryCode, context)
|
||||
{
|
||||
_loginWithRecoveryCodeForm = HtmlAssert.HasForm(loginWithRecoveryCode);
|
||||
|
|
@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account
|
|||
var indexPage = await Client.GetAsync(goToIndex);
|
||||
var index = await ResponseAssert.IsHtmlDocumentAsync(indexPage);
|
||||
|
||||
return new Index(Client, index, Context, authenticated: true);
|
||||
return new Index(Client, index, new DefaultUIContext(Context) { UserAuthenticated = true });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,19 +7,24 @@ using System.Net.Http;
|
|||
using System.Security.Cryptography;
|
||||
using System.Threading.Tasks;
|
||||
using AngleSharp.Dom.Html;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage
|
||||
{
|
||||
internal class EnableAuthenticator : HtmlPage
|
||||
internal class EnableAuthenticator : DefaultUIPage
|
||||
{
|
||||
public const string AuthenticatorKey = nameof(EnableAuthenticator) + "." + nameof(AuthenticatorKey);
|
||||
|
||||
private readonly IHtmlElement _codeElement;
|
||||
private readonly IHtmlFormElement _sendCodeForm;
|
||||
|
||||
public EnableAuthenticator(HttpClient client, IHtmlDocument enableAuthenticator, HtmlPageContext context)
|
||||
public EnableAuthenticator(
|
||||
HttpClient client,
|
||||
IHtmlDocument enableAuthenticator,
|
||||
DefaultUIContext context)
|
||||
: base(client, enableAuthenticator, context)
|
||||
{
|
||||
Assert.True(Context.UserAuthenticated);
|
||||
_codeElement = HtmlAssert.HasElement("kbd", enableAuthenticator);
|
||||
_sendCodeForm = HtmlAssert.HasForm("#send-code", enableAuthenticator);
|
||||
}
|
||||
|
|
@ -27,7 +32,7 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage
|
|||
internal async Task<ShowRecoveryCodes> SendValidCodeAsync()
|
||||
{
|
||||
var authenticatorKey = _codeElement.TextContent.Replace(" ", "");
|
||||
Context[AuthenticatorKey] = authenticatorKey;
|
||||
Context.AuthenticatorKey = authenticatorKey;
|
||||
var verificationCode = ComputeCode(authenticatorKey);
|
||||
|
||||
var sendCodeResponse = await Client.SendAsync(_sendCodeForm, new Dictionary<string, string>
|
||||
|
|
|
|||
|
|
@ -4,31 +4,34 @@
|
|||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using AngleSharp.Dom.Html;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage
|
||||
{
|
||||
public class Index : HtmlPage
|
||||
public class Index : DefaultUIPage
|
||||
{
|
||||
private readonly IHtmlAnchorElement _profileLink;
|
||||
private readonly IHtmlAnchorElement _changePasswordLink;
|
||||
private readonly IHtmlAnchorElement _twoFactorLink;
|
||||
private readonly IHtmlAnchorElement _personalDataLink;
|
||||
|
||||
public Index(HttpClient client, IHtmlDocument manage, HtmlPageContext context)
|
||||
public Index(HttpClient client, IHtmlDocument manage, DefaultUIContext context)
|
||||
: base(client, manage, context)
|
||||
{
|
||||
Assert.True(Context.UserAuthenticated);
|
||||
|
||||
_profileLink = HtmlAssert.HasLink("#profile", manage);
|
||||
_changePasswordLink = HtmlAssert.HasLink("#change-password", manage);
|
||||
_twoFactorLink = HtmlAssert.HasLink("#two-factor", manage);
|
||||
_personalDataLink = HtmlAssert.HasLink("#personal-data", manage);
|
||||
}
|
||||
|
||||
public async Task<TwoFactorAuthentication> ClickTwoFactorLinkAsync(bool twoFactorEnabled)
|
||||
public async Task<TwoFactorAuthentication> ClickTwoFactorLinkAsync()
|
||||
{
|
||||
var goToTwoFactor = await Client.GetAsync(_twoFactorLink.Href);
|
||||
var twoFactor = await ResponseAssert.IsHtmlDocumentAsync(goToTwoFactor);
|
||||
|
||||
return new TwoFactorAuthentication(Client, twoFactor, Context, twoFactorEnabled);
|
||||
return new TwoFactorAuthentication(Client, twoFactor, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,17 +8,15 @@ using AngleSharp.Dom.Html;
|
|||
|
||||
namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage
|
||||
{
|
||||
internal class ShowRecoveryCodes : HtmlPage
|
||||
internal class ShowRecoveryCodes : DefaultUIPage
|
||||
{
|
||||
public const string RecoveryCodes = nameof(ShowRecoveryCodes) + "." + nameof(RecoveryCodes);
|
||||
|
||||
private readonly IEnumerable<IHtmlElement> _recoveryCodeElements;
|
||||
|
||||
public ShowRecoveryCodes(HttpClient client, IHtmlDocument showRecoveryCodes, HtmlPageContext context)
|
||||
public ShowRecoveryCodes(HttpClient client, IHtmlDocument showRecoveryCodes, DefaultUIContext context)
|
||||
: base(client, showRecoveryCodes, context)
|
||||
{
|
||||
_recoveryCodeElements = HtmlAssert.HasElements(".recovery-code", showRecoveryCodes);
|
||||
Context[RecoveryCodes] = string.Join(" ", Codes);
|
||||
Context.RecoveryCodes = Codes.ToArray();
|
||||
}
|
||||
|
||||
public IEnumerable<string> Codes => _recoveryCodeElements.Select(rc => rc.TextContent);
|
||||
|
|
|
|||
|
|
@ -8,16 +8,14 @@ using Xunit;
|
|||
|
||||
namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage
|
||||
{
|
||||
public class TwoFactorAuthentication : HtmlPage
|
||||
public class TwoFactorAuthentication : DefaultUIPage
|
||||
{
|
||||
private readonly bool _twoFactorEnabled;
|
||||
private readonly IHtmlAnchorElement _enableAuthenticatorLink;
|
||||
|
||||
public TwoFactorAuthentication(HttpClient client, IHtmlDocument twoFactor, HtmlPageContext context, bool twoFactorEnabled)
|
||||
public TwoFactorAuthentication(HttpClient client, IHtmlDocument twoFactor, DefaultUIContext context)
|
||||
: base(client, twoFactor, context)
|
||||
{
|
||||
_twoFactorEnabled = twoFactorEnabled;
|
||||
if (!_twoFactorEnabled)
|
||||
if (!Context.TwoFactorEnabled)
|
||||
{
|
||||
_enableAuthenticatorLink = HtmlAssert.HasLink("#enable-authenticator", twoFactor);
|
||||
}
|
||||
|
|
@ -25,7 +23,7 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage
|
|||
|
||||
internal async Task<EnableAuthenticator> ClickEnableAuthenticatorLinkAsync()
|
||||
{
|
||||
Assert.False(_twoFactorEnabled);
|
||||
Assert.False(Context.TwoFactorEnabled);
|
||||
|
||||
var goToEnableAuthenticator = await Client.GetAsync(_enableAuthenticatorLink.Href);
|
||||
var enableAuthenticator = await ResponseAssert.IsHtmlDocumentAsync(goToEnableAuthenticator);
|
||||
|
|
|
|||
|
|
@ -9,11 +9,11 @@ using Xunit;
|
|||
|
||||
namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account
|
||||
{
|
||||
public class Register : HtmlPage
|
||||
public class Register : DefaultUIPage
|
||||
{
|
||||
private IHtmlFormElement _registerForm;
|
||||
|
||||
public Register(HttpClient client, IHtmlDocument register, HtmlPageContext context)
|
||||
public Register(HttpClient client, IHtmlDocument register, DefaultUIContext context)
|
||||
: base(client, register, context)
|
||||
{
|
||||
_registerForm = HtmlAssert.HasForm(register);
|
||||
|
|
@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account
|
|||
var indexResponse = await Client.GetAsync(registeredLocation);
|
||||
var index = await ResponseAssert.IsHtmlDocumentAsync(indexResponse);
|
||||
|
||||
return new Index(Client, index, Context, authenticated: true);
|
||||
return new Index(Client, index, Context.WithAuthenticatedUser());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using AngleSharp.Dom.Html;
|
||||
using Microsoft.AspNetCore.Identity.FunctionalTests.Pages.Account;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.FunctionalTests.Contoso
|
||||
{
|
||||
public class Login : DefaultUIPage
|
||||
{
|
||||
private readonly IHtmlFormElement _loginForm;
|
||||
|
||||
public Login(HttpClient client, IHtmlDocument login, DefaultUIContext context)
|
||||
: base(client, login, context)
|
||||
{
|
||||
_loginForm = HtmlAssert.HasForm(login);
|
||||
}
|
||||
|
||||
public async Task<ExternalLogin> SendNewUserNameAsync(string userName)
|
||||
{
|
||||
var externalLogin = await SendLoginForm(userName);
|
||||
|
||||
return new ExternalLogin(Client, externalLogin, Context);
|
||||
}
|
||||
|
||||
public async Task<Index> SendExistingUserNameAsync(string userName)
|
||||
{
|
||||
var externalLogin = await SendLoginForm(userName);
|
||||
|
||||
return new Index(Client, externalLogin, Context.WithAuthenticatedUser());
|
||||
}
|
||||
|
||||
private async Task<IHtmlDocument> SendLoginForm(string userName)
|
||||
{
|
||||
var contosoResponse = await Client.SendAsync(_loginForm, new Dictionary<string, string>
|
||||
{
|
||||
["Input_Login"] = userName
|
||||
});
|
||||
|
||||
var goToExternalLogin = ResponseAssert.IsRedirect(contosoResponse);
|
||||
var externalLogInResponse = await Client.GetAsync(goToExternalLogin);
|
||||
if (Context.ExistingUser)
|
||||
{
|
||||
var goToIndex = ResponseAssert.IsRedirect(externalLogInResponse);
|
||||
var indexResponse = await Client.GetAsync(goToIndex);
|
||||
return await ResponseAssert.IsHtmlDocumentAsync(indexResponse);
|
||||
}
|
||||
else
|
||||
{
|
||||
return await ResponseAssert.IsHtmlDocumentAsync(externalLogInResponse);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -9,19 +9,20 @@ using Xunit;
|
|||
|
||||
namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
||||
{
|
||||
public class Index : HtmlPage
|
||||
public class Index : DefaultUIPage
|
||||
{
|
||||
private readonly bool _authenticated;
|
||||
private readonly IHtmlAnchorElement _registerLink;
|
||||
private readonly IHtmlAnchorElement _loginLink;
|
||||
private readonly IHtmlAnchorElement _manageLink;
|
||||
public static readonly string Path = "/";
|
||||
|
||||
public Index(HttpClient client, IHtmlDocument index, HtmlPageContext context, bool authenticated)
|
||||
public Index(
|
||||
HttpClient client,
|
||||
IHtmlDocument index,
|
||||
DefaultUIContext context)
|
||||
: base(client, index, context)
|
||||
{
|
||||
_authenticated = authenticated;
|
||||
if (!_authenticated)
|
||||
if (!Context.UserAuthenticated)
|
||||
{
|
||||
_registerLink = HtmlAssert.HasLink("#register", Document);
|
||||
_loginLink = HtmlAssert.HasLink("#login", Document);
|
||||
|
|
@ -32,17 +33,17 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
}
|
||||
}
|
||||
|
||||
public static async Task<Index> CreateAsync(HttpClient client, bool authenticated = false)
|
||||
public static async Task<Index> CreateAsync(HttpClient client, DefaultUIContext context = null)
|
||||
{
|
||||
var goToIndex = await client.GetAsync("/");
|
||||
var index = await ResponseAssert.IsHtmlDocumentAsync(goToIndex);
|
||||
|
||||
return new Index(client, index, new HtmlPageContext(), authenticated);
|
||||
return new Index(client, index, context ?? new DefaultUIContext());
|
||||
}
|
||||
|
||||
public async Task<Register> ClickRegisterLinkAsync()
|
||||
{
|
||||
Assert.False(_authenticated);
|
||||
Assert.False(Context.UserAuthenticated);
|
||||
|
||||
var goToRegister = await Client.GetAsync(_registerLink.Href);
|
||||
var register = await ResponseAssert.IsHtmlDocumentAsync(goToRegister);
|
||||
|
|
@ -52,7 +53,7 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
|
||||
public async Task<Login> ClickLoginLinkAsync()
|
||||
{
|
||||
Assert.False(_authenticated);
|
||||
Assert.False(Context.UserAuthenticated);
|
||||
|
||||
var goToLogin = await Client.GetAsync(_loginLink.Href);
|
||||
var login = await ResponseAssert.IsHtmlDocumentAsync(goToLogin);
|
||||
|
|
@ -62,7 +63,7 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
|
||||
internal async Task<Account.Manage.Index> ClickManageLinkAsync()
|
||||
{
|
||||
Assert.True(_authenticated);
|
||||
Assert.True(Context.UserAuthenticated);
|
||||
|
||||
var goToManage = await Client.GetAsync(_manageLink.Href);
|
||||
var manage = await ResponseAssert.IsHtmlDocumentAsync(goToManage);
|
||||
|
|
|
|||
|
|
@ -21,5 +21,21 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
// Act & Assert
|
||||
await UserStories.RegisterNewUserAsync(client, userName, password);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanRegisterWithASocialLoginProvider()
|
||||
{
|
||||
// Arrange
|
||||
var server = ServerFactory.CreateServer(builder =>
|
||||
builder.ConfigureServices(services => services.SetupTestThirdPartyLogin()));
|
||||
var client = ServerFactory.CreateDefaultClient(server);
|
||||
|
||||
var guid = Guid.NewGuid();
|
||||
var userName = $"{guid}";
|
||||
var email = $"{guid}@example.com";
|
||||
|
||||
// Act & Assert
|
||||
await UserStories.RegisterNewUserWithSocialLoginAsync(client, userName, email);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,34 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
return await login.LoginValidUserAsync(userName, password);
|
||||
}
|
||||
|
||||
internal static async Task<Index> RegisterNewUserWithSocialLoginAsync(HttpClient client, string userName, string email)
|
||||
{
|
||||
var index = await Index.CreateAsync(client,new DefaultUIContext().WithSocialLoginEnabled());
|
||||
|
||||
var login = await index.ClickLoginLinkAsync();
|
||||
|
||||
var contosoLogin = await login.ClickLoginWithContosoLinkAsync();
|
||||
|
||||
var externalLogin = await contosoLogin.SendNewUserNameAsync(userName);
|
||||
|
||||
return await externalLogin.SendEmailAsync(email);
|
||||
}
|
||||
|
||||
internal static async Task<Index> LoginWithSocialLoginAsync(HttpClient client, string userName)
|
||||
{
|
||||
var index = await Index.CreateAsync(
|
||||
client,
|
||||
new DefaultUIContext()
|
||||
.WithSocialLoginEnabled()
|
||||
.WithExistingUser());
|
||||
|
||||
var login = await index.ClickLoginLinkAsync();
|
||||
|
||||
var contosoLogin = await login.ClickLoginWithContosoLinkAsync();
|
||||
|
||||
return await contosoLogin.SendExistingUserNameAsync(userName);
|
||||
}
|
||||
|
||||
internal static async Task<Index> LoginExistingUser2FaAsync(HttpClient client, string userName, string password, string twoFactorKey)
|
||||
{
|
||||
var index = await Index.CreateAsync(client);
|
||||
|
|
@ -41,12 +69,10 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
return await login2Fa.Send2FACodeAsync(twoFactorKey);
|
||||
}
|
||||
|
||||
internal static async Task<ShowRecoveryCodes> EnableTwoFactorAuthentication(
|
||||
Index index,
|
||||
bool twoFactorEnabled)
|
||||
internal static async Task<ShowRecoveryCodes> EnableTwoFactorAuthentication(Index index)
|
||||
{
|
||||
var manage = await index.ClickManageLinkAsync();
|
||||
var twoFactor = await manage.ClickTwoFactorLinkAsync(twoFactorEnabled);
|
||||
var twoFactor = await manage.ClickTwoFactorLinkAsync();
|
||||
var enableAuthenticator = await twoFactor.ClickEnableAuthenticatorLinkAsync();
|
||||
return await enableAuthenticator.SendValidCodeAsync();
|
||||
}
|
||||
|
|
@ -63,7 +89,7 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
|
||||
var login2Fa = await loginWithPassword.PasswordLoginValidUserWith2FaAsync(userName, password);
|
||||
|
||||
var loginRecoveryCode = await login2Fa.ClickRecoveryCodeLinkAsync();
|
||||
var loginRecoveryCode = await login2Fa.ClickRecoveryCodeLinkAsync();
|
||||
|
||||
return await loginRecoveryCode.SendRecoveryCodeAsync(recoveryCode);
|
||||
}
|
||||
|
|
|
|||
231
test/WebSites/Identity.DefaultUI.WebSite/Data/Migrations/20180217170630_UpdateIdentitySchema.Designer.cs
generated
Normal file
231
test/WebSites/Identity.DefaultUI.WebSite/Data/Migrations/20180217170630_UpdateIdentitySchema.Designer.cs
generated
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Internal;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using Microsoft.EntityFrameworkCore.Storage.Internal;
|
||||
|
||||
namespace Identity.DefaultUI.WebSite.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(IdentityDbContext))]
|
||||
[Migration("20180217170630_UpdateIdentitySchema")]
|
||||
partial class UpdateIdentitySchema
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "2.1.0-preview2-30103")
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasName("RoleNameIndex")
|
||||
.HasFilter("[NormalizedName] IS NOT NULL");
|
||||
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("AccessFailedCount");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<bool>("EmailConfirmed");
|
||||
|
||||
b.Property<bool>("LockoutEnabled");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("PasswordHash");
|
||||
|
||||
b.Property<string>("PhoneNumber");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed");
|
||||
|
||||
b.Property<string>("SecurityStamp");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasName("UserNameIndex")
|
||||
.HasFilter("[NormalizedUserName] IS NOT NULL");
|
||||
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("ProviderKey");
|
||||
|
||||
b.Property<string>("ProviderDisplayName");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("RoleId");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace Identity.DefaultUI.WebSite.Data.Migrations
|
||||
{
|
||||
public partial class UpdateIdentitySchema : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropIndex(
|
||||
name: "UserNameIndex",
|
||||
table: "AspNetUsers");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_AspNetUserRoles_UserId",
|
||||
table: "AspNetUserRoles");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "RoleNameIndex",
|
||||
table: "AspNetRoles");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "UserNameIndex",
|
||||
table: "AspNetUsers",
|
||||
column: "NormalizedUserName",
|
||||
unique: true,
|
||||
filter: "[NormalizedUserName] IS NOT NULL");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "RoleNameIndex",
|
||||
table: "AspNetRoles",
|
||||
column: "NormalizedName",
|
||||
unique: true,
|
||||
filter: "[NormalizedName] IS NOT NULL");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_AspNetUserTokens_AspNetUsers_UserId",
|
||||
table: "AspNetUserTokens",
|
||||
column: "UserId",
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_AspNetUserTokens_AspNetUsers_UserId",
|
||||
table: "AspNetUserTokens");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "UserNameIndex",
|
||||
table: "AspNetUsers");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "RoleNameIndex",
|
||||
table: "AspNetRoles");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "UserNameIndex",
|
||||
table: "AspNetUsers",
|
||||
column: "NormalizedUserName",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetUserRoles_UserId",
|
||||
table: "AspNetUserRoles",
|
||||
column: "UserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "RoleNameIndex",
|
||||
table: "AspNetRoles",
|
||||
column: "NormalizedName");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,13 @@
|
|||
// 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.
|
||||
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Internal;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using Microsoft.EntityFrameworkCore.Storage.Internal;
|
||||
|
||||
namespace Identity.DefaultUI.WebSite.Data.Migrations
|
||||
{
|
||||
|
|
@ -14,32 +16,36 @@ namespace Identity.DefaultUI.WebSite.Data.Migrations
|
|||
{
|
||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "1.0.0-rc3")
|
||||
.HasAnnotation("ProductVersion", "2.1.0-preview2-30103")
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole", b =>
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
{
|
||||
b.Property<string>("Id");
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasAnnotation("MaxLength", 256);
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasAnnotation("MaxLength", 256);
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.HasName("RoleNameIndex");
|
||||
.IsUnique()
|
||||
.HasName("RoleNameIndex")
|
||||
.HasFilter("[NormalizedName] IS NOT NULL");
|
||||
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim<string>", b =>
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
|
@ -58,7 +64,58 @@ namespace Identity.DefaultUI.WebSite.Data.Migrations
|
|||
b.ToTable("AspNetRoleClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim<string>", b =>
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("AccessFailedCount");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<bool>("EmailConfirmed");
|
||||
|
||||
b.Property<bool>("LockoutEnabled");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("PasswordHash");
|
||||
|
||||
b.Property<string>("PhoneNumber");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed");
|
||||
|
||||
b.Property<string>("SecurityStamp");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasName("UserNameIndex")
|
||||
.HasFilter("[NormalizedUserName] IS NOT NULL");
|
||||
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
|
@ -77,7 +134,7 @@ namespace Identity.DefaultUI.WebSite.Data.Migrations
|
|||
b.ToTable("AspNetUserClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin<string>", b =>
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
|
|
@ -95,7 +152,7 @@ namespace Identity.DefaultUI.WebSite.Data.Migrations
|
|||
b.ToTable("AspNetUserLogins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole<string>", b =>
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
|
|
@ -105,12 +162,10 @@ namespace Identity.DefaultUI.WebSite.Data.Migrations
|
|||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken<string>", b =>
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
|
|
@ -125,91 +180,51 @@ namespace Identity.DefaultUI.WebSite.Data.Migrations
|
|||
b.ToTable("AspNetUserTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.Property<string>("Id");
|
||||
|
||||
b.Property<int>("AccessFailedCount");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasAnnotation("MaxLength", 256);
|
||||
|
||||
b.Property<bool>("EmailConfirmed");
|
||||
|
||||
b.Property<bool>("LockoutEnabled");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasAnnotation("MaxLength", 256);
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasAnnotation("MaxLength", 256);
|
||||
|
||||
b.Property<string>("PasswordHash");
|
||||
|
||||
b.Property<string>("PhoneNumber");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed");
|
||||
|
||||
b.Property<string>("SecurityStamp");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasAnnotation("MaxLength", 256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasName("UserNameIndex");
|
||||
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole")
|
||||
.WithMany("Claims")
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim<string>", b =>
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
|
||||
.WithMany("Claims")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin<string>", b =>
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
|
||||
.WithMany("Logins")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole<string>", b =>
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole")
|
||||
.WithMany("Users")
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
|
||||
.WithMany("Roles")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,4 +39,8 @@
|
|||
<ProjectReference Include="..\..\..\src\UI\Microsoft.AspNetCore.Identity.UI.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="$(MicrosoftEntityFrameworkCoreToolsDotNetPackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
@page
|
||||
@model LoginModel
|
||||
@{
|
||||
Layout = "_Layout";
|
||||
ViewData["Title"] = "Contoso log-in";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"]</h2>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<section>
|
||||
<form method="post">
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Input.Login"></label>
|
||||
<input asp-for="Input.Login" class="form-control" />
|
||||
<span asp-validation-for="Input.Login" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="checkbox">
|
||||
<label asp-for="Input.RememberMe">
|
||||
<input asp-for="Input.RememberMe" />
|
||||
@Html.DisplayNameFor(m => m.Input.RememberMe)
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-default">Log in</button>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@section Scripts {
|
||||
<partial name="_ValidationScriptsPartial" />
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
// 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 Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Identity.DefaultUI.WebSite.Pages
|
||||
{
|
||||
public class LoginModel : PageModel
|
||||
{
|
||||
public LoginModel(IOptionsMonitor<ContosoAuthenticationOptions> options)
|
||||
{
|
||||
Options = options.CurrentValue;
|
||||
}
|
||||
|
||||
public class InputModel
|
||||
{
|
||||
[Required]
|
||||
public string Login { get; set; }
|
||||
public bool RememberMe { get; set; }
|
||||
}
|
||||
|
||||
[BindProperty]
|
||||
public InputModel Input { get; set; }
|
||||
|
||||
[BindProperty(SupportsGet = true)]
|
||||
public string ReturnUrl { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public string State { get; set; }
|
||||
|
||||
public ContosoAuthenticationOptions Options { get; }
|
||||
|
||||
public IActionResult OnGet()
|
||||
{
|
||||
return Page();
|
||||
}
|
||||
|
||||
public async Task<IActionResult> OnPostAsync()
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return Page();
|
||||
}
|
||||
else
|
||||
{
|
||||
var state = JsonConvert.DeserializeObject<IDictionary<string, string>>(State);
|
||||
var identity = new ClaimsIdentity(new Claim[]
|
||||
{
|
||||
new Claim(ClaimTypes.NameIdentifier, Input.Login)
|
||||
},
|
||||
state["LoginProvider"],
|
||||
ClaimTypes.NameIdentifier,
|
||||
ClaimTypes.Role);
|
||||
var principal = new ClaimsPrincipal(identity);
|
||||
var properties = new AuthenticationProperties(state)
|
||||
{
|
||||
IsPersistent = Input.RememberMe
|
||||
};
|
||||
await HttpContext.SignInAsync(Options.SignInScheme, principal, properties);
|
||||
return Redirect(ReturnUrl ?? "~/");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// 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;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
|
||||
namespace Identity.DefaultUI.WebSite
|
||||
{
|
||||
public static class ContosoAuthenticationBuilderExtensions
|
||||
{
|
||||
public static AuthenticationBuilder AddContosoAuthentication(
|
||||
this AuthenticationBuilder builder,
|
||||
Action<ContosoAuthenticationOptions> configure) =>
|
||||
builder.AddScheme<ContosoAuthenticationOptions, ContosoAuthenticationHandler>(
|
||||
ContosoAuthenticationConstants.Scheme,
|
||||
ContosoAuthenticationConstants.DisplayName,
|
||||
configure);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
// 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.
|
||||
|
||||
namespace Identity.DefaultUI.WebSite
|
||||
{
|
||||
public static class ContosoAuthenticationConstants
|
||||
{
|
||||
public const string Scheme = "Contoso";
|
||||
public const string DisplayName = "Contoso";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
// 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;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Identity.DefaultUI.WebSite
|
||||
{
|
||||
public class ContosoAuthenticationHandler : AuthenticationHandler<ContosoAuthenticationOptions>
|
||||
{
|
||||
public ContosoAuthenticationHandler(
|
||||
IOptionsMonitor<ContosoAuthenticationOptions> options,
|
||||
ILoggerFactory logger,
|
||||
UrlEncoder encoder,
|
||||
ISystemClock clock)
|
||||
: base(options, logger, encoder, clock)
|
||||
{
|
||||
}
|
||||
|
||||
protected override Task<AuthenticateResult> HandleAuthenticateAsync() =>
|
||||
Task.FromResult(AuthenticateResult.NoResult());
|
||||
|
||||
protected override Task HandleChallengeAsync(AuthenticationProperties properties)
|
||||
{
|
||||
var uri = $"{Request.Scheme}://{Request.Host}{Request.PathBase}{Options.RemoteLoginPath}";
|
||||
uri = QueryHelpers.AddQueryString(uri, new Dictionary<string, string>()
|
||||
{
|
||||
["State"] = JsonConvert.SerializeObject(properties.Items),
|
||||
[Options.ReturnUrlQueryParameter] = properties.RedirectUri
|
||||
});
|
||||
Response.Redirect(uri);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// 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 Microsoft.AspNetCore.Authentication;
|
||||
|
||||
namespace Identity.DefaultUI.WebSite
|
||||
{
|
||||
public class ContosoAuthenticationOptions : AuthenticationSchemeOptions
|
||||
{
|
||||
public ContosoAuthenticationOptions()
|
||||
{
|
||||
Events = new object();
|
||||
}
|
||||
|
||||
public string SignInScheme { get; set; }
|
||||
public string ReturnUrlQueryParameter { get; set; } = "returnUrl";
|
||||
public string RemoteLoginPath { get; set; } = "/Contoso/Login";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"ConnectionStrings": {
|
||||
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-Identity.DefaultUI.WebSite-53bc9b9d-9d6a-45d4-8429-2a2761773502;Trusted_Connection=True;MultipleActiveResultSets=true"
|
||||
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-Identity.DefaultUI.WebSite-90455f3b-6c48-4aa0-a8d6-294d8e0b3d4d;Trusted_Connection=True;MultipleActiveResultSets=true"
|
||||
//"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-Identity.DefaultUI.WebSite-53bc9b9d-9d6a-45d4-8429-2a2761773502;Trusted_Connection=True;MultipleActiveResultSets=true"
|
||||
},
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
|
|
|
|||
Loading…
Reference in New Issue