I am using Blazor 8 (server and with per component/ per page) and trying to tie windows authentication into it, but I can't get "NotAuthorized" to work.
Routes.razor
@using Microsoft.AspNetCore.Components.Authorization
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(Layout.MainLayout)">
<NotAuthorized>
Not Authroized
</NotAuthorized>
</AuthorizeRouteView>
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
</Found>
</Router>
Weather.razor
@page "/weather"
@using Microsoft.AspNetCore.Authorization
@attribute [StreamRendering]
@attribute [Authorize(Roles = "test")]
<PageTitle>Weather</PageTitle>
<h1>Weather</h1>
<p>This component demonstrates showing data.</p>
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
private WeatherForecast[]? forecasts;
protected override async Task OnInitializedAsync()
{
// Simulate asynchronous loading to demonstrate streaming rendering
await Task.Delay(500);
var startDate = DateOnly.FromDateTime(DateTime.Now);
var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };
forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = startDate.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = summaries[Random.Shared.Next(summaries.Length)]
}).ToArray();
}
private class WeatherForecast
{
public DateOnly Date { get; set; }
public int TemperatureC { get; set; }
public string? Summary { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
}
Program.cs
using BlazorApp11.Components;
using Microsoft.AspNetCore.Authentication.Negotiate;
namespace BlazorApp11
{
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme);
builder.Services.AddAuthorization(options =>
{
options.FallbackPolicy = options.DefaultPolicy;
});
builder.Services.AddCascadingAuthenticationState();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAntiforgery();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();
app.Run();
}
}
}
Am I missing something? When I go to the Weather Page, I get 403 Forbidden with none of my layout. I was expecting to see "Not Authroized"
I reproduced your issue and got a response :
I checked the NetWork tab in browser:
the .net 7 project:
.net 8 project:
It would send a request while it failed authorize,and the request would be blocked by the middleware
WorkAround:
Then I tried to customize the behavior of AuthorizationMiddleware,follow this document
public class MyAuthorizationMiddlewareResultHandler : IAuthorizationMiddlewareResultHandler
{
private readonly AuthorizationMiddlewareResultHandler defaultHandler = new();
public async Task HandleAsync(RequestDelegate next,HttpContext context,AuthorizationPolicy policy,PolicyAuthorizationResult authorizeResult)
{
// Fall back to the default implementation.
await defaultHandler.HandleAsync(next, context, policy, authorizeResult);
if (authorizeResult.Forbidden == true)
{
await next.Invoke(context);
}
}
}
.....
builder.Services.AddSingleton<IAuthorizationMiddlewareResultHandler, MyAuthorizationMiddlewareResultHandler>();
The content would be displayed now:
Update:
After some researching, I think the issue is mainly related with render mode,if you don't modify the default rendermode(Static Server) in app.razor,the parent component would work as a static page and always send a request ,and the request would be handled by middewares , when you haven't login/ not authorized, you would be redirected to target page like MVC/Razor Page
So another workaround is apply IteractiveServer render mode to the entire app:
<Routes @rendermode="new InteractiveServerRenderMode()"/>
Now when I try with Identity Template,I could see the custom content either: