I have written a web app using Windows Authentication. It uses the new(ish) Blazor Web App template, which means that there is a constant SignalR connection between server and client.
I found a scenario where the connection can be interrupted. When this happens it automatically reconnects however it now thinks it is unauthorized (e.g. where I am using an <AuthorizeView>
component).
To try and figure out why I've implemented a CircuitHandler, as follows:
public class UserCircuitHandler : CircuitHandler
{
private AuthenticationStateProvider authenticationStateProvider;
public UserCircuitHandler(AuthenticationStateProvider authenticationStateProvider)
{
this.authenticationStateProvider = authenticationStateProvider;
authenticationStateProvider.AuthenticationStateChanged += AuthenticationStateProvider_AuthenticationStateChanged;
}
public override Task OnCircuitClosedAsync(Circuit circuit, CancellationToken cancellationToken)
{
return base.OnCircuitClosedAsync(circuit, cancellationToken);
}
public override Task OnCircuitOpenedAsync(Circuit circuit, CancellationToken cancellationToken)
{
return base.OnCircuitOpenedAsync(circuit, cancellationToken);
}
public override Task OnConnectionDownAsync(Circuit circuit, CancellationToken cancellationToken)
{
return base.OnConnectionDownAsync(circuit, cancellationToken);
}
public override async Task OnConnectionUpAsync(Circuit circuit, CancellationToken cancellationToken)
{
await base.OnConnectionUpAsync(circuit, cancellationToken);
}
private async void AuthenticationStateProvider_AuthenticationStateChanged(Task<AuthenticationState> task)
{
//If I put a break point here, I can see that it does re-authenticate successfully.
}
}
And then register it in Program.cs
as follows:
services.AddScoped<CircuitHandler, UserCircuitHandler>();
If I put break-points in this, I can see that it detects when the connection goes down, comes back up, and the AuthenticationStateProvider event fires a couple of times, by the end of which it indicates that it has re-authenticated successfully. But yet the UI does not show the content of the <AuthorizeView>
. Why not?
I should add that in the Output section (Visual Studio 2022) I see the following appear a few times:
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService: Information: Authorization failed. Fail() was explicitly called.
For the record and in case anyone else experiences similar issues, the issue that breaks the connection is easily fixable. This was caused by SignalR receiving too much data at once over JS interop (default maximum is 32KB), and can be fixed as follows in Program.cs
:
builder.Services.Configure<HubOptions>(options =>
{
options.MaximumReceiveMessageSize = null;
});
I am just concerned that should a future scenario result in the same outcome, authentication is not automatically re-established.
Any advice is much appreciated.
I have written a web app using Windows Authentication. It uses the new(ish) Blazor Web App template, which means that there is a constant SignalR connection between server and client.
I found a scenario where the connection can be interrupted. When this happens it automatically reconnects however it now thinks it is unauthorized (e.g. where I am using an <AuthorizeView>
component).
To try and figure out why I've implemented a CircuitHandler, as follows:
public class UserCircuitHandler : CircuitHandler
{
private AuthenticationStateProvider authenticationStateProvider;
public UserCircuitHandler(AuthenticationStateProvider authenticationStateProvider)
{
this.authenticationStateProvider = authenticationStateProvider;
authenticationStateProvider.AuthenticationStateChanged += AuthenticationStateProvider_AuthenticationStateChanged;
}
public override Task OnCircuitClosedAsync(Circuit circuit, CancellationToken cancellationToken)
{
return base.OnCircuitClosedAsync(circuit, cancellationToken);
}
public override Task OnCircuitOpenedAsync(Circuit circuit, CancellationToken cancellationToken)
{
return base.OnCircuitOpenedAsync(circuit, cancellationToken);
}
public override Task OnConnectionDownAsync(Circuit circuit, CancellationToken cancellationToken)
{
return base.OnConnectionDownAsync(circuit, cancellationToken);
}
public override async Task OnConnectionUpAsync(Circuit circuit, CancellationToken cancellationToken)
{
await base.OnConnectionUpAsync(circuit, cancellationToken);
}
private async void AuthenticationStateProvider_AuthenticationStateChanged(Task<AuthenticationState> task)
{
//If I put a break point here, I can see that it does re-authenticate successfully.
}
}
And then register it in Program.cs
as follows:
services.AddScoped<CircuitHandler, UserCircuitHandler>();
If I put break-points in this, I can see that it detects when the connection goes down, comes back up, and the AuthenticationStateProvider event fires a couple of times, by the end of which it indicates that it has re-authenticated successfully. But yet the UI does not show the content of the <AuthorizeView>
. Why not?
I should add that in the Output section (Visual Studio 2022) I see the following appear a few times:
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService: Information: Authorization failed. Fail() was explicitly called.
For the record and in case anyone else experiences similar issues, the issue that breaks the connection is easily fixable. This was caused by SignalR receiving too much data at once over JS interop (default maximum is 32KB), and can be fixed as follows in Program.cs
:
builder.Services.Configure<HubOptions>(options =>
{
options.MaximumReceiveMessageSize = null;
});
I am just concerned that should a future scenario result in the same outcome, authentication is not automatically re-established.
Any advice is much appreciated.
Share Improve this question edited Nov 18, 2024 at 16:35 Greg asked Nov 18, 2024 at 16:28 GregGreg 1,7334 gold badges20 silver badges31 bronze badges 2- 1 maybe we could try to create a CustomAuthStateProvider, so that we could control the auth state manually? – Tiny Wang Commented Nov 19, 2024 at 9:56
- Hi, yes. I actually have done this, one for Windows Authentication and one for authentication via a database. However, I found what the issue was, I'll post an update shortly. Thanks. – Greg Commented Nov 26, 2024 at 10:41
1 Answer
Reset to default 0I managed to solve this issue.
The clue was in here:
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService: Information: Authorization failed. Fail() was explicitly called.
I had the following class handling authorization requirements, and this was where Fail()
was being called:
public class UserPermissionRequirementHandler : AuthorizationHandler<UserPermissionRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, UserPermissionRequirement requirement)
{
var user = User.FromClaimsPrincipal(context.User);
if (user != null && requirement.IsMet(user))
{
context.Succeed(requirement);
}
else
{
context.Fail();
}
return Task.CompletedTask;
}
}
When I simulated a connection failure with a breakpoint in this class, what I saw was that when the connection came back up context.User
would have none of the claims that I had assigned it, and so it was not authorised.
A workaround I've come up with, which I don't 100% like, but it works, is as follows:
When the connection goes down, store the user state. If the connection is subsequently closed, get rid of it, but if it comes back up, it can be retrieved and used to authorise the user.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745607624a4635762.html
评论列表(0条)