I have a bare-bones RemoteAuthenticationHandler
that I am going to build on, but I can't work out exactly what HandleRemoteAuthenticateAsync
should do for it to work.
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Options;
using System.Security.Claims;
using System.Text.Encodings.Web;
namespace BlazorAuthExample;
public class MyAuthOptions : RemoteAuthenticationOptions
{
public MyAuthOptions()
{
CallbackPath = new PathString("/signin-myauth");
}
}
public class MyAuthHandler : RemoteAuthenticationHandler<MyAuthOptions>
{
public MyAuthHandler(
IOptionsMonitor<MyAuthOptions> options,
ILoggerFactory logger,
UrlEncoder encoder) : base(options, logger, encoder)
{
}
protected override Task HandleChallengeAsync(AuthenticationProperties properties)
{
Context.Response.Redirect("/my-sign-in-page");
return Task.CompletedTask;
}
protected override Task<HandleRequestResult> HandleRemoteAuthenticateAsync()
{
var nameIdentifierClaim = new Claim(ClaimTypes.NameIdentifier, "mrpmorris@gmail.com", ClaimTypes.NameIdentifier, "myauth", "myauth");
var identity = new ClaimsIdentity([nameIdentifierClaim], "myauth");
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, "myauth");
return Task.FromResult(HandleRequestResult.Success(ticket));
}
}
Program.cs
findbuilder.Services.AddAuthentication(options =>
{
options.DefaultScheme = IdentityConstants.ApplicationScheme;
options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
})
.AddIdentityCookies();
and change it to
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = IdentityConstants.ApplicationScheme;
options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
})
.AddRemoteScheme<MyAuthOptions, MyAuthHandler>("myauth", "My auth", null)
.AddIdentityCookies();
MySignInPage.razor
with the following contents@page "/my-sign-in-page"
<form action="/signin-myauth" method="post">
<button type="submit">Click here to sign in</button>
</form>
Register
item in the nav menu on the leftMy auth
I now expect the same behaviour as I see when I sign into Google et al, but it seems nothing happens at all.
You are not handling RedirectUri
in your handler.
Add those two lines to your HandleRemoteAuthenticateAsync
method.
// hardcoded for sake of simplicity
ticket.Properties.RedirectUri = "/Account/ExternalLogin?ReturnUrl=&Action=LoginCallback";
ticket.Properties.Items.Add("LoginProvider", "myauth");
Ideally, you must pass RedirectUri from the challenge method (properties.RedirectUri
) to your login page and then to your handle method.
Updated:
Following is a sample implementation that supports the proper handling of RedirectUri
. Do not use this in your production.
public class MyAuthHandler : RemoteAuthenticationHandler<MyAuthOptions>
{
public MyAuthHandler(
IOptionsMonitor<MyAuthOptions> options,
ILoggerFactory logger,
UrlEncoder encoder) : base(options, logger, encoder)
{
}
protected override Task HandleChallengeAsync(AuthenticationProperties properties)
{
var url = "/my-sign-in-page?RedirectUri=" + Uri.EscapeDataString(properties.RedirectUri ?? "");
if (properties.Items.TryGetValue("XsrfId", out var xsrfId))
{
url += "&xsrfId=" + xsrfId;
}
Context.Response.Redirect(url);
return Task.CompletedTask;
}
protected override Task<HandleRequestResult> HandleRemoteAuthenticateAsync()
{
var nameIdentifierClaim = new Claim(ClaimTypes.NameIdentifier, "mrpmorris@gmail.com", ClaimTypes.NameIdentifier, "myauth", "myauth");
var identity = new ClaimsIdentity([nameIdentifierClaim], "myauth");
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, "myauth");
ticket.Properties.RedirectUri = Context.Request.Form["RedirectUri"];
ticket.Properties.Items.Add("LoginProvider", "myauth");
if (Context.Request.Form.TryGetValue("XsrfId", out var xsrfId))
{
ticket.Properties.Items.Add("XsrfId", xsrfId);
}
return Task.FromResult(HandleRequestResult.Success(ticket));
}
}
@page "/my-sign-in-page"
<form action="/signin-myauth" method="post">
<input type="hidden" name="RedirectUri" value="@RedirectUri"/>
<input type="hidden" name="XsrfId" value="@XsrfId"/>
<button type="submit">Click here to sign in</button>
</form>
@code {
[SupplyParameterFromQuery]
private string? RedirectUri { get; set; }
[SupplyParameterFromQuery]
private string? XsrfId { get; set; }
}