Blazor 文件夹授权不起作用,允许未登录的用户查看内容

Blazor folder authorization not working, allows non-logged in users to see content

最新的 blazor .NET blazor。 Program.cs

using APICommon;
using Common.Settings;
using EventApiService;
using Events.Application.Commands.Coins;
using FluentValidation;
using Identity.Application.Commands;
using Identity.Persistence;

using MediatR;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Serilog;

var builder = WebApplication.CreateBuilder(args);

//Serilog
builder.WebHost.UseSerilog((hostingContext, loggerConfiguration) => loggerConfiguration
    .ReadFrom.Configuration(hostingContext.Configuration)
    .Enrich.FromLogContext());

//code removed

builder.Services.AddCustomAuthorization(dbSettings);
builder.Services.AddHttpClient();

builder.Services.AddRazorPages(options =>
    {
        options.Conventions.AuthorizeFolder("/admin",  "Administrators");
        options.Conventions.AuthorizeFolder("/client",  "Owners");

    }
);
builder.Services.AddServerSideBlazor();



builder.Services.AddTelerikBlazor();


builder.Services.AddScoped<AuthenticationStateProvider, RevalidatingIdentityAuthenticationStateProvider<IdentityUser>>();
var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");

app.Run();
internal static class ExtensionMethods
{

    public static IServiceCollection AddCustomAuthorization(this IServiceCollection services,
        DatabaseSettings dbSettings)
    {
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(dbSettings.IdentityConnectionString));

        services.AddDatabaseDeveloperPageExceptionFilter();

        services.AddDefaultIdentity<ApplicationUser>(options =>
            {
                options.SignIn.RequireConfirmedAccount = true;
                options.Password.RequiredLength = 6;
                options.Password.RequireDigit = false;
                options.Password.RequireLowercase = false;
                options.Password.RequiredUniqueChars = 0;
                options.Password.RequireNonAlphanumeric = false;
                options.Password.RequireUppercase = false;
            })
            .AddRoles<IdentityRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>();

      
   
        return services;
    }
}

以上假设是为了确保只有授权的“所有者”角色才能看到 /client 或其中的任何页面,但即使我不登录,我也可以点击 /client 并查看其内容。

我认为你不应该在 Blazor 中使用它:

builder.Services.AddRazorPages(options =>
    {
        options.Conventions.AuthorizeFolder("/admin",  "Administrators");
        options.Conventions.AuthorizeFolder("/client",  "Owners");

    }
);

相反,您应该应用授权属性,如下所示:

[Authorize(Roles = "Administrators")]

ya i have the above in one of the pages and it works, but I dont want to repeat this in every page, and in case a page is added in the future i want to make sure be default its protected if its under the folder

在这种情况下,您可以将 Authorize 属性放在 _Imports.razor 文件中,从而为您的所有页面启用该属性。您还可以使用 Authorize 属性定义组件基 class,并从该 class 派生所有组件页面。这种技术更为常见,因为您可以将所有页面的其他共同点放在基础 class 中。这就是 Blazor 的方法。您尝试做的实际上在 MVC 或 Razor 页面中很常见,但不适用于 Blazor。

Blazor 不支持授权“文件夹”。您将需要授权组件。 处理此问题的一种方法是对所有管理元素使用 AdminPanelComponent,并在该组件上应用管理授权规则。

由于您使用的是 Blazor 服务器,因此您可以匹配路由并使用中间件应用授权。示例:

app.Use(async (context, next) =>
{
    if(context.Request.Path.StartsWithSegments("/admin", System.StringComparison.OrdinalIgnoreCase))
    {
        if (!context.User.IsAdministrator()) // ext. method... replace with your own logic
        {
            await context.ForbidAsync();
            return;
        }
    }
    if(context.Request.Path.StartsWithSegments("/client", System.StringComparison.OrdinalIgnoreCase))
    {
        if (!context.User.IsOwner()) 
        {
            await context.ForbidAsync();
            return;
        }
    }
    await next.Invoke();
});

(如果您愿意,可以将其重构为 own middleware class。)