Components auth step 2 (#10293)
* CR feedback left over from #10227 * Begin adding E2E test case * Add cookie auth and test login page * Make E2E auth component work client-side too * Restructure auth E2E tests around a router so there can easily be multiple such test components * Add E2E test case for AuthorizeView * Prepare for E2E test implementations * Fix ToBaseRelativePath handling of hashes ... otherwise E2E test will fail, because we're using the hash to control server-or-client execution * Decouple E2E execution mode from hosting mode * Actual E2E tests for cascading authentication state * Actual E2E tests for AuthorizeView (in "no authentication rule" mode) * Fix inconsistent namespace * CR: Manual ref assembly definitions for AuthorizeView/CascadingAuthenticationState
This commit is contained in:
parent
5502c2080e
commit
147880f796
|
|
@ -4,6 +4,8 @@ T:Microsoft.AspNetCore.Components.RenderTree.RenderTreeFrame
|
||||||
T:Microsoft.AspNetCore.Mvc.ApplicationModels.PageParameterModel
|
T:Microsoft.AspNetCore.Mvc.ApplicationModels.PageParameterModel
|
||||||
T:Microsoft.AspNetCore.Mvc.ApplicationModels.PagePropertyModel
|
T:Microsoft.AspNetCore.Mvc.ApplicationModels.PagePropertyModel
|
||||||
# Manually implemented - https://github.com/aspnet/AspNetCore/issues/8825
|
# Manually implemented - https://github.com/aspnet/AspNetCore/issues/8825
|
||||||
|
T:Microsoft.AspNetCore.Components.AuthorizeView
|
||||||
|
T:Microsoft.AspNetCore.Components.CascadingAuthenticationState
|
||||||
T:Microsoft.AspNetCore.Components.CascadingValue`1
|
T:Microsoft.AspNetCore.Components.CascadingValue`1
|
||||||
T:Microsoft.AspNetCore.Components.Forms.DataAnnotationsValidator
|
T:Microsoft.AspNetCore.Components.Forms.DataAnnotationsValidator
|
||||||
T:Microsoft.AspNetCore.Components.Forms.EditForm
|
T:Microsoft.AspNetCore.Components.Forms.EditForm
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,9 @@ namespace Microsoft.AspNetCore.Blazor.Services.Test
|
||||||
[InlineData("scheme://host/path/", "scheme://host/path/", "")]
|
[InlineData("scheme://host/path/", "scheme://host/path/", "")]
|
||||||
[InlineData("scheme://host/path/", "scheme://host/path/more", "more")]
|
[InlineData("scheme://host/path/", "scheme://host/path/more", "more")]
|
||||||
[InlineData("scheme://host/path/", "scheme://host/path", "")]
|
[InlineData("scheme://host/path/", "scheme://host/path", "")]
|
||||||
|
[InlineData("scheme://host/path/", "scheme://host/path#hash", "#hash")]
|
||||||
|
[InlineData("scheme://host/path/", "scheme://host/path/#hash", "#hash")]
|
||||||
|
[InlineData("scheme://host/path/", "scheme://host/path/more#hash", "more#hash")]
|
||||||
public void ComputesCorrectValidBaseRelativePaths(string baseUri, string absoluteUri, string expectedResult)
|
public void ComputesCorrectValidBaseRelativePaths(string baseUri, string absoluteUri, string expectedResult)
|
||||||
{
|
{
|
||||||
var actualResult = _uriHelper.ToBaseRelativePath(baseUri, absoluteUri);
|
var actualResult = _uriHelper.ToBaseRelativePath(baseUri, absoluteUri);
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,32 @@ namespace Microsoft.AspNetCore.Components.RenderTree
|
||||||
// Built-in components: https://github.com/aspnet/AspNetCore/issues/8825
|
// Built-in components: https://github.com/aspnet/AspNetCore/issues/8825
|
||||||
namespace Microsoft.AspNetCore.Components
|
namespace Microsoft.AspNetCore.Components
|
||||||
{
|
{
|
||||||
|
public partial class AuthorizeView : Microsoft.AspNetCore.Components.ComponentBase
|
||||||
|
{
|
||||||
|
public AuthorizeView() { }
|
||||||
|
[Microsoft.AspNetCore.Components.ParameterAttribute]
|
||||||
|
public Microsoft.AspNetCore.Components.RenderFragment<Microsoft.AspNetCore.Components.AuthenticationState> Authorized { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } private set { throw null; } }
|
||||||
|
[Microsoft.AspNetCore.Components.ParameterAttribute]
|
||||||
|
public Microsoft.AspNetCore.Components.RenderFragment Authorizing { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } private set { throw null; } }
|
||||||
|
[Microsoft.AspNetCore.Components.ParameterAttribute]
|
||||||
|
public Microsoft.AspNetCore.Components.RenderFragment<Microsoft.AspNetCore.Components.AuthenticationState> ChildContent { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } private set { throw null; } }
|
||||||
|
[Microsoft.AspNetCore.Components.ParameterAttribute]
|
||||||
|
public Microsoft.AspNetCore.Components.RenderFragment NotAuthorized { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } private set { throw null; } }
|
||||||
|
protected override void BuildRenderTree(Microsoft.AspNetCore.Components.RenderTree.RenderTreeBuilder builder) { }
|
||||||
|
[System.Diagnostics.DebuggerStepThroughAttribute]
|
||||||
|
protected override System.Threading.Tasks.Task OnParametersSetAsync() { throw null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class CascadingAuthenticationState : Microsoft.AspNetCore.Components.ComponentBase, System.IDisposable
|
||||||
|
{
|
||||||
|
public CascadingAuthenticationState() { }
|
||||||
|
[Microsoft.AspNetCore.Components.ParameterAttribute]
|
||||||
|
public Microsoft.AspNetCore.Components.RenderFragment ChildContent { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } private set { throw null; } }
|
||||||
|
protected override void BuildRenderTree(Microsoft.AspNetCore.Components.RenderTree.RenderTreeBuilder builder) { }
|
||||||
|
protected override void OnInit() { }
|
||||||
|
void System.IDisposable.Dispose() { }
|
||||||
|
}
|
||||||
|
|
||||||
public partial class CascadingValue<T> : Microsoft.AspNetCore.Components.IComponent
|
public partial class CascadingValue<T> : Microsoft.AspNetCore.Components.IComponent
|
||||||
{
|
{
|
||||||
public CascadingValue() { }
|
public CascadingValue() { }
|
||||||
|
|
|
||||||
|
|
@ -16,21 +16,6 @@ namespace Microsoft.AspNetCore.Components
|
||||||
public abstract System.Threading.Tasks.Task<Microsoft.AspNetCore.Components.AuthenticationState> GetAuthenticationStateAsync();
|
public abstract System.Threading.Tasks.Task<Microsoft.AspNetCore.Components.AuthenticationState> GetAuthenticationStateAsync();
|
||||||
protected void NotifyAuthenticationStateChanged(System.Threading.Tasks.Task<Microsoft.AspNetCore.Components.AuthenticationState> task) { }
|
protected void NotifyAuthenticationStateChanged(System.Threading.Tasks.Task<Microsoft.AspNetCore.Components.AuthenticationState> task) { }
|
||||||
}
|
}
|
||||||
public partial class AuthorizeView : Microsoft.AspNetCore.Components.ComponentBase
|
|
||||||
{
|
|
||||||
public AuthorizeView() { }
|
|
||||||
[Microsoft.AspNetCore.Components.ParameterAttribute]
|
|
||||||
public Microsoft.AspNetCore.Components.RenderFragment<Microsoft.AspNetCore.Components.AuthenticationState> Authorized { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
|
||||||
[Microsoft.AspNetCore.Components.ParameterAttribute]
|
|
||||||
public Microsoft.AspNetCore.Components.RenderFragment Authorizing { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
|
||||||
[Microsoft.AspNetCore.Components.ParameterAttribute]
|
|
||||||
public Microsoft.AspNetCore.Components.RenderFragment<Microsoft.AspNetCore.Components.AuthenticationState> ChildContent { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
|
||||||
[Microsoft.AspNetCore.Components.ParameterAttribute]
|
|
||||||
public Microsoft.AspNetCore.Components.RenderFragment NotAuthorized { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
|
||||||
protected override void BuildRenderTree(Microsoft.AspNetCore.Components.RenderTree.RenderTreeBuilder builder) { }
|
|
||||||
[System.Diagnostics.DebuggerStepThroughAttribute]
|
|
||||||
protected override System.Threading.Tasks.Task OnParametersSetAsync() { throw null; }
|
|
||||||
}
|
|
||||||
[Microsoft.AspNetCore.Components.BindElementAttribute("select", null, "value", "onchange")]
|
[Microsoft.AspNetCore.Components.BindElementAttribute("select", null, "value", "onchange")]
|
||||||
[Microsoft.AspNetCore.Components.BindElementAttribute("textarea", null, "value", "onchange")]
|
[Microsoft.AspNetCore.Components.BindElementAttribute("textarea", null, "value", "onchange")]
|
||||||
[Microsoft.AspNetCore.Components.BindInputElementAttribute("checkbox", null, "checked", "onchange")]
|
[Microsoft.AspNetCore.Components.BindInputElementAttribute("checkbox", null, "checked", "onchange")]
|
||||||
|
|
@ -85,15 +70,6 @@ namespace Microsoft.AspNetCore.Components
|
||||||
public static System.Action<Microsoft.AspNetCore.Components.UIEventArgs> SetValueHandler(System.Action<string> setter, string existingValue) { throw null; }
|
public static System.Action<Microsoft.AspNetCore.Components.UIEventArgs> SetValueHandler(System.Action<string> setter, string existingValue) { throw null; }
|
||||||
public static System.Action<Microsoft.AspNetCore.Components.UIEventArgs> SetValueHandler<T>(System.Action<T> setter, T existingValue) { throw null; }
|
public static System.Action<Microsoft.AspNetCore.Components.UIEventArgs> SetValueHandler<T>(System.Action<T> setter, T existingValue) { throw null; }
|
||||||
}
|
}
|
||||||
public partial class CascadingAuthenticationState : Microsoft.AspNetCore.Components.ComponentBase, System.IDisposable
|
|
||||||
{
|
|
||||||
public CascadingAuthenticationState() { }
|
|
||||||
[Microsoft.AspNetCore.Components.ParameterAttribute]
|
|
||||||
public Microsoft.AspNetCore.Components.RenderFragment ChildContent { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
|
||||||
protected override void BuildRenderTree(Microsoft.AspNetCore.Components.RenderTree.RenderTreeBuilder builder) { }
|
|
||||||
protected override void OnInit() { }
|
|
||||||
void System.IDisposable.Dispose() { }
|
|
||||||
}
|
|
||||||
[System.AttributeUsageAttribute(System.AttributeTargets.Property, AllowMultiple=false, Inherited=false)]
|
[System.AttributeUsageAttribute(System.AttributeTargets.Property, AllowMultiple=false, Inherited=false)]
|
||||||
public sealed partial class CascadingParameterAttribute : System.Attribute
|
public sealed partial class CascadingParameterAttribute : System.Attribute
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,6 @@ namespace Microsoft.AspNetCore.Components
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class AuthenticationState
|
public class AuthenticationState
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Gets a <see cref="ClaimsPrincipal"/> that describes the current user.
|
|
||||||
/// </summary>
|
|
||||||
public ClaimsPrincipal User { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs an instance of <see cref="AuthenticationState"/>.
|
/// Constructs an instance of <see cref="AuthenticationState"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -24,5 +19,10 @@ namespace Microsoft.AspNetCore.Components
|
||||||
{
|
{
|
||||||
User = user ?? throw new ArgumentNullException(nameof(user));
|
User = user ?? throw new ArgumentNullException(nameof(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a <see cref="ClaimsPrincipal"/> that describes the current user.
|
||||||
|
/// </summary>
|
||||||
|
public ClaimsPrincipal User { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,19 +12,16 @@ namespace Microsoft.AspNetCore.Components
|
||||||
public abstract class AuthenticationStateProvider
|
public abstract class AuthenticationStateProvider
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets an <see cref="AuthenticationState"/> instance that describes
|
/// Asynchronously gets an <see cref="AuthenticationState"/> that describes the current user.
|
||||||
/// the current user.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>An <see cref="AuthenticationState"/> instance that describes the current user.</returns>
|
/// <returns>A task that, when resolved, gives an <see cref="AuthenticationState"/> instance that describes the current user.</returns>
|
||||||
public abstract Task<AuthenticationState> GetAuthenticationStateAsync();
|
public abstract Task<AuthenticationState> GetAuthenticationStateAsync();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An event that provides notification when the <see cref="AuthenticationState"/>
|
/// An event that provides notification when the <see cref="AuthenticationState"/>
|
||||||
/// has changed. For example, this event may be raised if a user logs in or out.
|
/// has changed. For example, this event may be raised if a user logs in or out.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
#pragma warning disable 0067 // "Never used" (it's only raised by subclasses)
|
|
||||||
public event AuthenticationStateChangedHandler AuthenticationStateChanged;
|
public event AuthenticationStateChangedHandler AuthenticationStateChanged;
|
||||||
#pragma warning restore 0067
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Raises the <see cref="AuthenticationStateChanged"/> event.
|
/// Raises the <see cref="AuthenticationStateChanged"/> event.
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,10 @@ namespace Microsoft.AspNetCore.Components
|
||||||
// baseUri ends with a slash), and from that we return "something"
|
// baseUri ends with a slash), and from that we return "something"
|
||||||
return locationAbsolute.Substring(baseUri.Length);
|
return locationAbsolute.Substring(baseUri.Length);
|
||||||
}
|
}
|
||||||
else if ($"{locationAbsolute}/".Equals(baseUri, StringComparison.Ordinal))
|
|
||||||
|
var hashIndex = locationAbsolute.IndexOf('#');
|
||||||
|
var locationAbsoluteNoHash = hashIndex < 0 ? locationAbsolute : locationAbsolute.Substring(0, hashIndex);
|
||||||
|
if ($"{locationAbsoluteNoHash}/".Equals(baseUri, StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
// Special case: for the base URI "/something/", if you're at
|
// Special case: for the base URI "/something/", if you're at
|
||||||
// "/something" then treat it as if you were at "/something/" (i.e.,
|
// "/something" then treat it as if you were at "/something/" (i.e.,
|
||||||
|
|
@ -162,7 +165,7 @@ namespace Microsoft.AspNetCore.Components
|
||||||
// whether the server would return the same page whether or not the
|
// whether the server would return the same page whether or not the
|
||||||
// slash is present, but ASP.NET Core at least does by default when
|
// slash is present, but ASP.NET Core at least does by default when
|
||||||
// using PathBase.
|
// using PathBase.
|
||||||
return string.Empty;
|
return locationAbsolute.Substring(baseUri.Length - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
var message = $"The URI '{locationAbsolute}' is not contained by the base URI '{baseUri}'.";
|
var message = $"The URI '{locationAbsolute}' is not contained by the base URI '{baseUri}'.";
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Infrastructure
|
||||||
public class BasicTestAppTestBase : ServerTestBase<ToggleExecutionModeServerFixture<Program>>
|
public class BasicTestAppTestBase : ServerTestBase<ToggleExecutionModeServerFixture<Program>>
|
||||||
{
|
{
|
||||||
public string ServerPathBase
|
public string ServerPathBase
|
||||||
=> "/subdir" + (_serverFixture.UsingAspNetHost ? "#server" : "");
|
=> "/subdir" + (_serverFixture.ExecutionMode == ExecutionMode.Server ? "#server" : "");
|
||||||
|
|
||||||
public BasicTestAppTestBase(
|
public BasicTestAppTestBase(
|
||||||
BrowserFixture browserFixture,
|
BrowserFixture browserFixture,
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,8 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures
|
||||||
: ServerFixture
|
: ServerFixture
|
||||||
{
|
{
|
||||||
public string PathBase { get; set; }
|
public string PathBase { get; set; }
|
||||||
public bool UsingAspNetHost { get; private set; }
|
|
||||||
|
public ExecutionMode ExecutionMode { get; set; } = ExecutionMode.Client;
|
||||||
|
|
||||||
private AspNetSiteServerFixture.BuildWebHost _buildWebHostMethod;
|
private AspNetSiteServerFixture.BuildWebHost _buildWebHostMethod;
|
||||||
private IDisposable _serverToDispose;
|
private IDisposable _serverToDispose;
|
||||||
|
|
@ -18,7 +19,6 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures
|
||||||
{
|
{
|
||||||
_buildWebHostMethod = buildWebHostMethod
|
_buildWebHostMethod = buildWebHostMethod
|
||||||
?? throw new ArgumentNullException(nameof(buildWebHostMethod));
|
?? throw new ArgumentNullException(nameof(buildWebHostMethod));
|
||||||
UsingAspNetHost = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string StartAndGetRootUri()
|
protected override string StartAndGetRootUri()
|
||||||
|
|
@ -46,4 +46,6 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures
|
||||||
_serverToDispose?.Dispose();
|
_serverToDispose?.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum ExecutionMode { Client, Server }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ using OpenQA.Selenium;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Components.E2ETests.ServerExecutionTests
|
namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
|
||||||
{
|
{
|
||||||
public class PrerenderingTest : ServerTestBase<AspNetSiteServerFixture>
|
public class PrerenderingTest : ServerTestBase<AspNetSiteServerFixture>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
|
||||||
public static ToggleExecutionModeServerFixture<T> WithServerExecution<T>(this ToggleExecutionModeServerFixture<T> serverFixture)
|
public static ToggleExecutionModeServerFixture<T> WithServerExecution<T>(this ToggleExecutionModeServerFixture<T> serverFixture)
|
||||||
{
|
{
|
||||||
serverFixture.UseAspNetHost(TestServer.Program.BuildWebHost);
|
serverFixture.UseAspNetHost(TestServer.Program.BuildWebHost);
|
||||||
|
serverFixture.ExecutionMode = ExecutionMode.Server;
|
||||||
return serverFixture;
|
return serverFixture;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -81,4 +81,12 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ServerAuthTest : AuthTest
|
||||||
|
{
|
||||||
|
public ServerAuthTest(BrowserFixture browserFixture, ToggleExecutionModeServerFixture<Program> serverFixture, ITestOutputHelper output)
|
||||||
|
: base(browserFixture, serverFixture.WithServerExecution(), output)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,92 @@
|
||||||
|
// 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 BasicTestApp;
|
||||||
|
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure;
|
||||||
|
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
|
||||||
|
using Microsoft.AspNetCore.E2ETesting;
|
||||||
|
using OpenQA.Selenium;
|
||||||
|
using Xunit;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
||||||
|
{
|
||||||
|
public class AuthTest : BasicTestAppTestBase
|
||||||
|
{
|
||||||
|
// These strings correspond to the links in BasicTestApp\AuthTest\Links.razor
|
||||||
|
const string CascadingAuthenticationStateLink = "Cascading authentication state";
|
||||||
|
const string AuthorizeViewCases = "AuthorizeView cases";
|
||||||
|
|
||||||
|
public AuthTest(
|
||||||
|
BrowserFixture browserFixture,
|
||||||
|
ToggleExecutionModeServerFixture<Program> serverFixture,
|
||||||
|
ITestOutputHelper output)
|
||||||
|
: base(browserFixture, serverFixture, output)
|
||||||
|
{
|
||||||
|
// Normally, the E2E tests use the Blazor dev server if they are testing
|
||||||
|
// client-side execution. But for the auth tests, we always have to run
|
||||||
|
// in "hosted on ASP.NET Core" mode, because we get the auth state from it.
|
||||||
|
serverFixture.UseAspNetHost(TestServer.Program.BuildWebHost);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CascadingAuthenticationState_Unauthenticated()
|
||||||
|
{
|
||||||
|
SignInAs(null);
|
||||||
|
|
||||||
|
var appElement = MountAndNavigateToAuthTest(CascadingAuthenticationStateLink);
|
||||||
|
|
||||||
|
Browser.Equal("False", () => appElement.FindElement(By.Id("identity-authenticated")).Text);
|
||||||
|
Browser.Equal(string.Empty, () => appElement.FindElement(By.Id("identity-name")).Text);
|
||||||
|
Browser.Equal("(none)", () => appElement.FindElement(By.Id("test-claim")).Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CascadingAuthenticationState_Authenticated()
|
||||||
|
{
|
||||||
|
SignInAs("someone cool");
|
||||||
|
|
||||||
|
var appElement = MountAndNavigateToAuthTest(CascadingAuthenticationStateLink);
|
||||||
|
|
||||||
|
Browser.Equal("True", () => appElement.FindElement(By.Id("identity-authenticated")).Text);
|
||||||
|
Browser.Equal("someone cool", () => appElement.FindElement(By.Id("identity-name")).Text);
|
||||||
|
Browser.Equal("Test claim value", () => appElement.FindElement(By.Id("test-claim")).Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AuthorizeViewCases_NoAuthorizationRule_Unauthenticated()
|
||||||
|
{
|
||||||
|
SignInAs(null);
|
||||||
|
MountAndNavigateToAuthTest(AuthorizeViewCases);
|
||||||
|
WaitUntilExists(By.CssSelector("#no-authorization-rule .not-authorized"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AuthorizeViewCases_NoAuthorizationRule_Authenticated()
|
||||||
|
{
|
||||||
|
SignInAs("Some User");
|
||||||
|
var appElement = MountAndNavigateToAuthTest(AuthorizeViewCases);
|
||||||
|
Browser.Equal("Welcome, Some User!", () =>
|
||||||
|
appElement.FindElement(By.CssSelector("#no-authorization-rule .authorized")).Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
IWebElement MountAndNavigateToAuthTest(string authLinkText)
|
||||||
|
{
|
||||||
|
Navigate(ServerPathBase);
|
||||||
|
var appElement = MountTestComponent<BasicTestApp.AuthTest.AuthRouter>();
|
||||||
|
WaitUntilExists(By.Id("auth-links"));
|
||||||
|
appElement.FindElement(By.LinkText(authLinkText)).Click();
|
||||||
|
return appElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SignInAs(string usernameOrNull)
|
||||||
|
{
|
||||||
|
const string authenticationPageUrl = "/Authentication";
|
||||||
|
var baseRelativeUri = usernameOrNull == null
|
||||||
|
? $"{authenticationPageUrl}?signout=true"
|
||||||
|
: $"{authenticationPageUrl}?username={usernameOrNull}";
|
||||||
|
Navigate(baseRelativeUri);
|
||||||
|
WaitUntilExists(By.CssSelector("h1#authentication"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
||||||
protected override void InitializeAsyncCore()
|
protected override void InitializeAsyncCore()
|
||||||
{
|
{
|
||||||
// On WebAssembly, page reloads are expensive so skip if possible
|
// On WebAssembly, page reloads are expensive so skip if possible
|
||||||
Navigate(ServerPathBase, noReload: !_serverFixture.UsingAspNetHost);
|
Navigate(ServerPathBase, noReload: _serverFixture.ExecutionMode == ExecutionMode.Client);
|
||||||
MountTestComponent<BindCasesComponent>();
|
MountTestComponent<BindCasesComponent>();
|
||||||
WaitUntilExists(By.Id("bind-cases"));
|
WaitUntilExists(By.Id("bind-cases"));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
||||||
|
|
||||||
protected override void InitializeAsyncCore()
|
protected override void InitializeAsyncCore()
|
||||||
{
|
{
|
||||||
Navigate(ServerPathBase, noReload: !_serverFixture.UsingAspNetHost);
|
Navigate(ServerPathBase, noReload: _serverFixture.ExecutionMode == ExecutionMode.Client);
|
||||||
MountTestComponent<BasicTestApp.CascadingValueTest.CascadingValueSupplier>();
|
MountTestComponent<BasicTestApp.CascadingValueTest.CascadingValueSupplier>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
||||||
|
|
||||||
protected override void InitializeAsyncCore()
|
protected override void InitializeAsyncCore()
|
||||||
{
|
{
|
||||||
Navigate(ServerPathBase, noReload: !_serverFixture.UsingAspNetHost);
|
Navigate(ServerPathBase, noReload: _serverFixture.ExecutionMode == ExecutionMode.Client);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
||||||
|
|
||||||
protected override void InitializeAsyncCore()
|
protected override void InitializeAsyncCore()
|
||||||
{
|
{
|
||||||
Navigate(ServerPathBase, noReload: !_serverFixture.UsingAspNetHost);
|
Navigate(ServerPathBase, noReload: _serverFixture.ExecutionMode == ExecutionMode.Client);
|
||||||
MountTestComponent<EventBubblingComponent>();
|
MountTestComponent<EventBubblingComponent>();
|
||||||
WaitUntilExists(By.Id("event-bubbling"));
|
WaitUntilExists(By.Id("event-bubbling"));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
||||||
protected override void InitializeAsyncCore()
|
protected override void InitializeAsyncCore()
|
||||||
{
|
{
|
||||||
// On WebAssembly, page reloads are expensive so skip if possible
|
// On WebAssembly, page reloads are expensive so skip if possible
|
||||||
Navigate(ServerPathBase, noReload: !_serverFixture.UsingAspNetHost);
|
Navigate(ServerPathBase, noReload: _serverFixture.ExecutionMode == ExecutionMode.Client);
|
||||||
MountTestComponent<BasicTestApp.EventCallbackTest.EventCallbackCases>();
|
MountTestComponent<BasicTestApp.EventCallbackTest.EventCallbackCases>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
||||||
protected override void InitializeAsyncCore()
|
protected override void InitializeAsyncCore()
|
||||||
{
|
{
|
||||||
// On WebAssembly, page reloads are expensive so skip if possible
|
// On WebAssembly, page reloads are expensive so skip if possible
|
||||||
Navigate(ServerPathBase, noReload: !_serverFixture.UsingAspNetHost);
|
Navigate(ServerPathBase, noReload: _serverFixture.ExecutionMode == ExecutionMode.Client);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
||||||
|
|
||||||
// Include the sync assertions only when running under WebAssembly
|
// Include the sync assertions only when running under WebAssembly
|
||||||
var expectedValues = expectedAsyncValues;
|
var expectedValues = expectedAsyncValues;
|
||||||
if (!_serverFixture.UsingAspNetHost)
|
if (_serverFixture.ExecutionMode == ExecutionMode.Client)
|
||||||
{
|
{
|
||||||
foreach (var kvp in expectedSyncValues)
|
foreach (var kvp in expectedSyncValues)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
||||||
protected override void InitializeAsyncCore()
|
protected override void InitializeAsyncCore()
|
||||||
{
|
{
|
||||||
// On WebAssembly, page reloads are expensive so skip if possible
|
// On WebAssembly, page reloads are expensive so skip if possible
|
||||||
Navigate(ServerPathBase, noReload: !_serverFixture.UsingAspNetHost);
|
Navigate(ServerPathBase, noReload: _serverFixture.ExecutionMode == ExecutionMode.Client);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
@page "/AuthHome"
|
||||||
|
|
||||||
|
Select an auth test below.
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
@using Microsoft.AspNetCore.Components.Routing
|
||||||
|
@inject IUriHelper UriHelper
|
||||||
|
|
||||||
|
@*
|
||||||
|
This router is independent of any other router that may exist within the same project.
|
||||||
|
It exists so that (1) we can easily have multiple test cases that depend on the
|
||||||
|
CascadingAuthenticationState, and (2) we can test the integration between the router
|
||||||
|
and @page authorization rules.
|
||||||
|
*@
|
||||||
|
|
||||||
|
<CascadingAuthenticationState>
|
||||||
|
<Router AppAssembly=typeof(BasicTestApp.Program).Assembly />
|
||||||
|
</CascadingAuthenticationState>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
<Links />
|
||||||
|
|
||||||
|
@functions {
|
||||||
|
protected override void OnInit()
|
||||||
|
{
|
||||||
|
// Start at AuthHome, not at any other component in the same app that happens to
|
||||||
|
// register itself for the route ""
|
||||||
|
var absoluteUriPath = new Uri(UriHelper.GetAbsoluteUri()).GetLeftPart(UriPartial.Path);
|
||||||
|
var relativeUri = UriHelper.ToBaseRelativePath(UriHelper.GetBaseUri(), absoluteUriPath);
|
||||||
|
if (relativeUri == string.Empty)
|
||||||
|
{
|
||||||
|
UriHelper.NavigateTo("AuthHome");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
@page "/AuthorizeViewCases"
|
||||||
|
|
||||||
|
<div id="no-authorization-rule">
|
||||||
|
<h3>Scenario: No authorization rule</h3>
|
||||||
|
|
||||||
|
<AuthorizeView>
|
||||||
|
<Authorizing>
|
||||||
|
<p class="authorizing">Authorizing...</p>
|
||||||
|
</Authorizing>
|
||||||
|
<Authorized>
|
||||||
|
<p class="authorized">Welcome, @context.User.Identity.Name!</p>
|
||||||
|
</Authorized>
|
||||||
|
<NotAuthorized>
|
||||||
|
<p class="not-authorized">You're not logged in.</p>
|
||||||
|
</NotAuthorized>
|
||||||
|
</AuthorizeView>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
@page "/CascadingAuthenticationStateConsumer"
|
||||||
|
@using System.Security.Claims
|
||||||
|
|
||||||
|
<h1>Cascading authentication state</h1>
|
||||||
|
|
||||||
|
@if (user == null)
|
||||||
|
{
|
||||||
|
<span id="auth-state-pending">Requesting authentication state...</span>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<p>
|
||||||
|
Authenticated:
|
||||||
|
<strong id="identity-authenticated">@user.Identity.IsAuthenticated</strong>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Name:
|
||||||
|
<strong id="identity-name">@user.Identity.Name</strong>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Test claim:
|
||||||
|
@if (user.HasClaim(TestClaimPredicate) == true)
|
||||||
|
{
|
||||||
|
<strong id="test-claim">@user.Claims.Single(c => TestClaimPredicate(c)).Value</strong>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<strong id="test-claim">(none)</strong>
|
||||||
|
}
|
||||||
|
</p>
|
||||||
|
}
|
||||||
|
|
||||||
|
@functions
|
||||||
|
{
|
||||||
|
static Predicate<Claim> TestClaimPredicate = c => c.Type == "test-claim";
|
||||||
|
|
||||||
|
ClaimsPrincipal user;
|
||||||
|
|
||||||
|
[CascadingParameter] Task<AuthenticationState> AuthenticationStateTask { get; set; }
|
||||||
|
|
||||||
|
protected override async Task OnParametersSetAsync()
|
||||||
|
{
|
||||||
|
user = (await AuthenticationStateTask).User;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
namespace BasicTestApp.AuthTest
|
||||||
|
{
|
||||||
|
// DTO shared between server and client
|
||||||
|
public class ClientSideAuthenticationStateData
|
||||||
|
{
|
||||||
|
public bool IsAuthenticated { get; set; }
|
||||||
|
|
||||||
|
public string UserName { get; set; }
|
||||||
|
|
||||||
|
public Dictionary<string, string> ExposedClaims { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
@using Microsoft.AspNetCore.Components.Routing
|
||||||
|
<ul id="auth-links">
|
||||||
|
<li><NavLink href="AuthHome" Match=NavLinkMatch.All>Home</NavLink></li>
|
||||||
|
<li><NavLink href="CascadingAuthenticationStateConsumer">Cascading authentication state</NavLink></li>
|
||||||
|
<li><NavLink href="AuthorizeViewCases">AuthorizeView cases</NavLink></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>To change the underlying authentication state, <a target="_blank" href="/Authentication">go here</a>.</p>
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
// 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.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
|
namespace BasicTestApp.AuthTest
|
||||||
|
{
|
||||||
|
// This is intended to be similar to the authentication stateprovider included by default
|
||||||
|
// with the client-side Blazor "Hosted in ASP.NET Core" template
|
||||||
|
public class ServerAuthenticationStateProvider : AuthenticationStateProvider
|
||||||
|
{
|
||||||
|
private readonly HttpClient _httpClient;
|
||||||
|
|
||||||
|
public ServerAuthenticationStateProvider(HttpClient httpClient)
|
||||||
|
{
|
||||||
|
_httpClient = httpClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
|
||||||
|
{
|
||||||
|
var uri = new Uri(_httpClient.BaseAddress, "/api/User");
|
||||||
|
var data = await _httpClient.GetJsonAsync<ClientSideAuthenticationStateData>(uri.AbsoluteUri);
|
||||||
|
ClaimsIdentity identity;
|
||||||
|
if (data.IsAuthenticated)
|
||||||
|
{
|
||||||
|
var claims = new[] { new Claim(ClaimTypes.Name, data.UserName) }
|
||||||
|
.Concat(data.ExposedClaims.Select(c => new Claim(c.Key, c.Value)));
|
||||||
|
identity = new ClaimsIdentity(claims, "Server authentication");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
identity = new ClaimsIdentity();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AuthenticationState(new ClaimsPrincipal(identity));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -54,6 +54,8 @@
|
||||||
<option value="BasicTestApp.KeyCasesComponent">Key cases</option>
|
<option value="BasicTestApp.KeyCasesComponent">Key cases</option>
|
||||||
<option value="BasicTestApp.ReorderingFocusComponent">Reordering focus retention</option>
|
<option value="BasicTestApp.ReorderingFocusComponent">Reordering focus retention</option>
|
||||||
<option value="BasicTestApp.RouterTest.UriHelperComponent">UriHelper Test</option>
|
<option value="BasicTestApp.RouterTest.UriHelperComponent">UriHelper Test</option>
|
||||||
|
<option value="BasicTestApp.AuthTest.CascadingAuthenticationStateParent">Cascading authentication state</option>
|
||||||
|
<option value="BasicTestApp.AuthTest.AuthRouter">Auth cases</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
@if (SelectedComponentType != null)
|
@if (SelectedComponentType != null)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using BasicTestApp.AuthTest;
|
||||||
using Microsoft.AspNetCore.Blazor.Http;
|
using Microsoft.AspNetCore.Blazor.Http;
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
using Microsoft.AspNetCore.Components.Builder;
|
using Microsoft.AspNetCore.Components.Builder;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
|
@ -12,6 +14,7 @@ namespace BasicTestApp
|
||||||
{
|
{
|
||||||
public void ConfigureServices(IServiceCollection services)
|
public void ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
|
services.AddSingleton<AuthenticationStateProvider, ServerAuthenticationStateProvider>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Configure(IComponentsApplicationBuilder app)
|
public void Configure(IComponentsApplicationBuilder app)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Microsoft.AspNetCore" />
|
<Reference Include="Microsoft.AspNetCore" />
|
||||||
|
<Reference Include="Microsoft.AspNetCore.Authentication.Cookies" />
|
||||||
<Reference Include="Microsoft.AspNetCore.Blazor.Server" />
|
<Reference Include="Microsoft.AspNetCore.Blazor.Server" />
|
||||||
<Reference Include="Microsoft.AspNetCore.Cors" />
|
<Reference Include="Microsoft.AspNetCore.Cors" />
|
||||||
<Reference Include="Microsoft.AspNetCore.Mvc" />
|
<Reference Include="Microsoft.AspNetCore.Mvc" />
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
using System.Linq;
|
||||||
|
using BasicTestApp.AuthTest;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace Components.TestServer.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
public class UserController : Controller
|
||||||
|
{
|
||||||
|
// GET api/user
|
||||||
|
[HttpGet]
|
||||||
|
public ClientSideAuthenticationStateData Get()
|
||||||
|
{
|
||||||
|
// Servers are not expected to expose everything from the server-side ClaimsPrincipal
|
||||||
|
// to the client. It's up to the developer to choose what kind of authentication state
|
||||||
|
// data is needed on the client so it can display suitable options in the UI.
|
||||||
|
|
||||||
|
return new ClientSideAuthenticationStateData
|
||||||
|
{
|
||||||
|
IsAuthenticated = User.Identity.IsAuthenticated,
|
||||||
|
UserName = User.Identity.Name,
|
||||||
|
ExposedClaims = User.Claims
|
||||||
|
.Where(c => c.Type == "test-claim")
|
||||||
|
.ToDictionary(c => c.Type, c => c.Value)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
@page
|
||||||
|
@using Microsoft.AspNetCore.Authentication
|
||||||
|
@using System.Security.Claims
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Authentication</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1 id="authentication">Authentication</h1>
|
||||||
|
<p>
|
||||||
|
This is a completely fake login mechanism for automated test purposes.
|
||||||
|
It accepts any username, with no password.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>Obviously you should not do this in real applications.</strong>
|
||||||
|
See also: <a href="https://docs.microsoft.com/aspnet/core/security">documentation on configuring a real login system.</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<h3>Sign in</h3>
|
||||||
|
|
||||||
|
@* Do not use method="get" for real login forms. This is just to simplify E2E tests. *@
|
||||||
|
<form method="get">
|
||||||
|
<p>
|
||||||
|
User name:
|
||||||
|
<input name="username" />
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<h3>Status</h3>
|
||||||
|
<p>
|
||||||
|
Authenticated: <strong>@User.Identity.IsAuthenticated</strong>
|
||||||
|
Username: <strong>@User.Identity.Name</strong>
|
||||||
|
</p>
|
||||||
|
<a href="Authentication?signout=true">Sign out</a>
|
||||||
|
</fieldset>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
@functions {
|
||||||
|
public async Task<IActionResult> OnGet()
|
||||||
|
{
|
||||||
|
if (Request.Query["signout"] == "true")
|
||||||
|
{
|
||||||
|
await HttpContext.SignOutAsync();
|
||||||
|
return Redirect("Authentication");
|
||||||
|
}
|
||||||
|
|
||||||
|
var username = Request.Query["username"];
|
||||||
|
if (!string.IsNullOrEmpty(username))
|
||||||
|
{
|
||||||
|
var claims = new List<Claim>
|
||||||
|
{
|
||||||
|
new Claim(ClaimTypes.Name, username),
|
||||||
|
new Claim("test-claim", "Test claim value"),
|
||||||
|
};
|
||||||
|
|
||||||
|
await HttpContext.SignInAsync(
|
||||||
|
new ClaimsPrincipal(new ClaimsIdentity(claims, "FakeAuthenticationType")));
|
||||||
|
|
||||||
|
return Redirect("Authentication");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Page();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using BasicTestApp;
|
using BasicTestApp;
|
||||||
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Components.Server;
|
using Microsoft.AspNetCore.Components.Server;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
|
@ -28,6 +29,7 @@ namespace TestServer
|
||||||
options.AddPolicy("AllowAll", _ => { /* Controlled below */ });
|
options.AddPolicy("AllowAll", _ => { /* Controlled below */ });
|
||||||
});
|
});
|
||||||
services.AddServerSideBlazor();
|
services.AddServerSideBlazor();
|
||||||
|
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
|
|
@ -50,6 +52,7 @@ namespace TestServer
|
||||||
.AllowCredentials();
|
.AllowCredentials();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.UseAuthentication();
|
||||||
|
|
||||||
// Mount the server-side Blazor app on /subdir
|
// Mount the server-side Blazor app on /subdir
|
||||||
app.Map("/subdir", subdirApp =>
|
app.Map("/subdir", subdirApp =>
|
||||||
|
|
@ -70,6 +73,7 @@ namespace TestServer
|
||||||
app.UseEndpoints(endpoints =>
|
app.UseEndpoints(endpoints =>
|
||||||
{
|
{
|
||||||
endpoints.MapControllers();
|
endpoints.MapControllers();
|
||||||
|
endpoints.MapRazorPages();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Separately, mount a prerendered server-side Blazor app on /prerendered
|
// Separately, mount a prerendered server-side Blazor app on /prerendered
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue