After weeks of research, I am still running into the wall....
My objective is: After the Windows authentication, invoke a custom application authorization process which will provide the ClaimsPrincipal for Blazor to perform role-based authorization.
In my Blazor's program.cs, I am using the Windows Authentication and have an Event to "react" to the authentication:
builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
.AddNegotiate(
options => {
options.Events =
new CMAPNegotiateEvents(builder.Environment);
});
I also have a custom AuthenticationStateProvider with a method to absorb the ClaimsPrincipal .
If I perform the custom authentication in the WhenAuthenticated() event, how do I invoke the AuthenticationStateProvider?
PS I don't want to use the Microsoft's MVC authentication model, because we already have our own model established.
I think I understand what you are trying to do so here's my shot at answering it.
I've used the standard Server template with Windows Authentication as my base. The complete VS solution is here: https://github.com/ShaunCurtis/SO73545707
It's all in the AuthenticationStateProvider
. Mine:
ServerAuthenticationStateProvider
rather than AuthenticationStateProvider
so we can call the base method and get the state.ClaimsIdentity
with the relevant information to the existing ClaimsPrincipal
.AuthenticationState
based on the updated ClaimsPrincipal
.using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Server;
using Microsoft.AspNetCore.Connections.Features;
using System.Security.Claims;
namespace SO73545707.Data
{
// Inherit from ServerAuthenticationStateProvider
public class MyAuthenticationStateProvider : ServerAuthenticationStateProvider
{
public async override Task<AuthenticationState> GetAuthenticationStateAsync()
{
// Call the base to get the AuthState and the user provided in the Security Headers by the server
var authstate = await base.GetAuthenticationStateAsync();
var user = authstate.User;
if (user is not null)
{
// Do whatever you want here to retrieve the additional user information you want to
// include in the ClaimsPrincipal - probably some form of Identity Service
// Construct a ClaimsIdentity instance to attach to the ClaimsPrincipal
var myIdentity = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Role, "User") });
// Add it to the existing ClaimsPrincipal
user.AddIdentity(myIdentity);
}
// construct a new state with the updated ClaimsPrincipal
// - or an empty one of you didn't get a user in the first place
// All the Authorization components and classes will now use this ClaimsPrincipal
return new AuthenticationState(user ?? new ClaimsPrincipal());
}
}
}
The service registration looks like this:
// Add services to the container.
builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
.AddNegotiate();
builder.Services.AddAuthorization(options =>
{
// By default, all incoming requests will be authorized according to the default policy.
options.FallbackPolicy = options.DefaultPolicy;
});
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
// must be after AddServerSideBlazor
builder.Services.AddScoped<AuthenticationStateProvider, MyAuthenticationStateProvider>();
builder.Services.AddSingleton<WeatherForecastService>();
I've added some Authorize
attributes to the standard pages to test it.
@attribute [Authorize(Roles = "User")]
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.