Xác thực cửa sổ Blazor với xác nhận quyền sở hữu tùy chỉnh

lập trình


Nè mọi người,

Tôi không biết liệu mình có làm sai hoàn toàn hay không nhưng điều tôi đang cố gắng đạt được là Lưu trữ ứng dụng máy chủ Blazor trên IIS của mình bằng Xác thực Windows và một tùy chỉnh bổ sung để ngăn mọi người truy cập, nhưng chỉ có một số ít người.

Cho đến nay tôi đã tìm đến đoạn mã được dán bên dưới và vấn đề là nó hoạt động với studio trực quan của tôi trong khi gỡ lỗi. Ở đó mọi thứ đều ổn và thực hiện công việc như mong đợi, nhưng ngay khi tôi xuất bản nó lên Máy chủ IIS, nó sẽ hạn chế quyền truy cập của tôi.

Nếu có ai có thể dẫn tôi đi đúng hướng thì tôi sẽ rất hạnh phúc.

Cảm ơn trước!

Những gì tôi đã thử:

Mã để ủy quyền cho người dùng (program.cs)

using System.Security.Claims;
using System.Security.Principal;
using ImsServerMonitor.Data;
using Microsoft.AspNetCore.Authentication.Negotiate;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
    .AddNegotiate(options =>
    {
        options.Events = new NegotiateEvents
        {
            OnAuthenticated = context =>
            {
                if (context.Principal.Identity is WindowsIdentity windowsIdentity)
                {
                    string loginName = windowsIdentity.Name;
                    
                    if (loginName.Contains("User1")
                        || loginName.Contains("User2")
                        || loginName.Contains("User3")
                        || loginName.Contains("User4"))
                    {
                        var claims = new List<Claim>
                        {
                            new Claim("CustomClaim", "Admin")
                        };

                        context.Principal.AddIdentity(new ClaimsIdentity(claims));
                    }
                }

                return Task.CompletedTask;
            }
        };
    });
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("AdminOnly", policyBuilder => policyBuilder.RequireClaim("CustomClaim", "Admin"));
    // By default, all incoming requests will be authorized according to the default policy.
    //options.FallbackPolicy = options.DefaultPolicy;
    options.FallbackPolicy = options.GetPolicy("AdminOnly");
});

builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<MonitorEngine>();
builder.Services.AddDevExpressBlazor();

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.UseRouting();

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

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

app.Run();

Ngoài ra, trên IIS ofc, tôi đã bật WindowsAuth cho trang web này và đã xác minh rằng Nhà cung cấp đàm phán nằm ở đầu danh sách.

Nhưng tôi thực sự không hiểu vấn đề là gì, ngay cả ChatGpt cũng làm tôi thất vọng… hoặc tôi đã không hỏi đúng câu hỏi.

Giải pháp 1

Những gì thực sự cần phải làm… sau một nghiên cứu may mắn và kiểm tra lần gỡ lỗi của bạn:

chương trình.cs cần trỏ đến trình xác thực tùy chỉnh với lược đồ tùy chỉnh->

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = "CustomWindowsAuthentication";
}).AddScheme<CustomWindowsAuthenticationOptions, CustomWindowsAuthenticationHandler>("CustomWindowsAuthentication", null);

Sau đó, bạn thực sự cần một lớp bổ sung để xử lý những thứ đó:

public class CustomWindowsAuthenticationHandler : AuthenticationHandler<CustomWindowsAuthenticationOptions>
    {
        public CustomWindowsAuthenticationHandler(
            IOptionsMonitor<CustomWindowsAuthenticationOptions> options,
            ILoggerFactory logger,
            UrlEncoder encoder,
            ISystemClock clock)
            : base(options, logger, encoder, clock)
        {
        }

        protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
        {
            if (!Context.User.Identity.IsAuthenticated || !(Context.User.Identity is WindowsIdentity windowsIdentity))
            {
                return AuthenticateResult.NoResult();
            }

            var loginName = windowsIdentity.Name;
            if (loginName.Contains("User1")
                || loginName.Contains("User2")
                || loginName.Contains("User3")
                || loginName.Contains("User4"))
            {
                var claims = new List<Claim>
                {
                    new Claim("CustomClaim", "Admin")
                };

                var identity = new ClaimsIdentity(claims, Scheme.Name);
                var principal = new ClaimsPrincipal(identity);

                var ticket = new AuthenticationTicket(principal, Scheme.Name);
                return AuthenticateResult.Success(ticket);
            }

            return AuthenticateResult.Fail("Custom authentication failed.");
        }
    }

Và để hoàn thiện, “CustomWindowsAuthenticationOptions” vì bạn cũng cần điều đó, mặc dù nó trống vì tôi không cần bất kỳ tùy chọn siêu đặc biệt nào.

public class CustomWindowsAuthenticationOptions : AuthenticationSchemeOptions
    {
        
    }

Giải pháp 4

Cảm ơn bạn cho câu hỏi và giải pháp này. Hoạt động tuyệt vời. Tôi đang dùng .NET 8 và phải thực hiện 1 thay đổi nhỏ trong đoạn mã bên dưới từ

var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, Scheme.Name);
return AuthenticateResult.Success(ticket);

ĐẾN

Context.User.AddIdentity(identity);
var ticket = new AuthenticationTicket(Context.User, Scheme.Name);
return AuthenticateResult.Success(ticket);

Nếu không, bạn không thể truy cập tên người dùng ở nơi khác trong mã.
Trong mã bên dưới _authMessage trả về null nếu chúng ta sử dụng mã gốc.

@code {
    [CascadingParameter]
    private Task<AuthenticationState>? AuthenticationState { get; set; }

    protected override async Task OnInitializedAsync()
    {
        if (AuthenticationState is not null)
        {
            var authState = await AuthenticationState;
            var user = authState.User;

            if (user?.Identity is not null && user.Identity.IsAuthenticated)
            {
                _authMessage = user.Identity.Name;
            }
        }
    }

コメント

タイトルとURLをコピーしました