I wanted to use the NotAuthorized
attribute in the <AuthorizeRouteView>
tag to redirect to the login page every time a non logged-in user try to access a page.
Howewer, it requires a RenderFragment<AuthentificationState>
typed parameter. What shoud I put to set this parameter to render the login page ?
Edit : Code is pretty simple. I used the Blazor server side project template with identity stored in application, just added the RedirectToLogin.razor
like this :
@inject NavigationManager NavigationManager
@code {
protected override void OnAfterRender()
{
NavigationManager.NavigateTo("counter"); //for an unknown reason, the "Identity/Account/Login" redirect doesn't work.
}
}
And modified the App.razor
:
<CascadingAuthenticationState>
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
<NotAuthorized>
@if(true) { } //Used for breakpoint.
<RedirectToLogin />
</NotAuthorized>
<Authorizing>
@if(true) { } //Used for breakpoint.
</Authorizing>
</AuthorizeRouteView>
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</CascadingAuthenticationState>
I didn't touch the Startup.cs
so it look like this :
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddScoped<AuthenticationStateProvider, RevalidatingIdentityAuthenticationStateProvider<IdentityUser>>();
services.AddSingleton<WeatherForecastService>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
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.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
}
What you can do in Blazor is use the information associated with the user through the authentication process to authorize what a user is (or isn't) allowed to do. ... You do that by, back in the App.cs file, replacing the RouteView component inside the Router's Found element with an AuthorizeRouteView component.
A NotAuthorized element that allows you to control what part of the UI is delivered to the user when they're not authorized An Authorizing element that displays a message if the user's information isn't available yet
Unlike the RouteView component, the AuthorizeRouteView looks at who's allowed to use a component and won't let users access components they're not authorized for. Here's the markup inside an App.cs file that does that:
Initialize a new instance of a AuthorizeRouteView. The content that will be displayed while asynchronous authorization is in progress. Gets or sets the type of a layout to be used if the page does not declare any layout. If specified, the type must implement IComponent and accept a parameter named Body.
I struggled with a similar issue where my <NotAuthorized>
part in app.razor was not being displayed for a user that was not authorized. After 3 days of pulling my hair out, I also was going for the solution in the MainLayout.razor as mentioned in other answers. One last attempt with a clean project, made my aware of how poor a programmer I am because I finally found the answer.
I did not read the documentation entirely, in which I could find the cause of the problem. On the following page: https://docs.microsoft.com/en-us/aspnet/core/blazor/security/?view=aspnetcore-5.0#customize-unauthorized-content-with-the-router-component you find how the NotAuthorized part is invoked. I totally missed the second bullet point:
The Router component, in conjunction with the AuthorizeRouteView component, allows the app to specify custom content if:
- Content isn't found.
- The user fails an [Authorize] condition applied to the component. The [Authorize] attribute is covered in the [Authorize] attribute section.
- Asynchronous authentication is in progress.
This means the <NotAuthorized>
part is only invoked/displayed when the route endpoint has a Authorize tag. In my case the route was going to my index page, without an Authorize tag....
Thanks to MartinH, I did not spend 3 days pulling my hair out.
For anyone else requiring clarification on the 'Authorize attrtibute', here's an example...
VerifyAuth.razor
@page "/verifyauth"
@attribute [Authorize] @*<--RIGHT HERE!!!*@
<div class="container">
<h3 class="text-center">Verify Auth</h3>
</div>
@code {
}
App.razor
<Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true">
<Found Context="routeData">
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" >
<Authorizing>
<text>Please wait, we are authorizing you...</text>
</Authorizing>
<NotAuthorized>
@if (context.User.Identity.IsAuthenticated == false)
{
<RedirectToLogin />
}
else
{
<p>You are not authorized to access this resource.</p>
}
</NotAuthorized>
</AuthorizeRouteView>
</Found>
<NotFound>
<CascadingAuthenticationState>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there is nothing at this address.</p>
</LayoutView>
</CascadingAuthenticationState>
</NotFound>
</Router>
RedirectToLogin.razor
@inject NavigationManager NavManager
@code {
protected override void OnInitialized()
{
NavManager.NavigateTo("/login");
}
}
Reference: https://docs.microsoft.com/en-us/aspnet/core/blazor/security/?view=aspnetcore-5.0#customize-unauthorized-content-with-the-router-component
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With