Сервер Blazor, атрибут авторизации с AuthenticationStateProvider не работаетC#

Место общения программистов C#
Ответить
Anonymous
 Сервер Blazor, атрибут авторизации с AuthenticationStateProvider не работает

Сообщение Anonymous »

Попытка реализовать аутентификацию и авторизацию с помощью AuthenticationStateProvider. После долгих экспериментов большая часть этого работает. У меня возникла пара проблем:
  • Если я обновлю страницу, авторизация полностью потеряется, и мне придется войти заново.
  • Механизм атрибутов, похоже, не работает, например после входа в систему и перехода на страницу с этим атрибутом меня отправляет обратно на страницу входа. :
    @attribute [Authorize(Roles = "SuperAdmin")]
Не уверен, доступен ли атрибут при использовании AuthenticationStateProvider, я не видел примеров их совместного использования. Еще один момент: мне нужно использовать интерактивный режим для некоторых страниц из-за использования Blazorise.
Код выглядит следующим образом:
Program.cs

Код: Выделить всё

using Blazored.Toast;
using Blazorise;
using Blazorise.Bootstrap5;
using Blazorise.Icons.FontAwesome;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Components.Authorization;

// This is a Blazor Server Application (NOT a Webassembly App)
var builder = WebApplication.CreateBuilder(args);

// Add service defaults & Aspire components.
builder.AddServiceDefaults();

// Add services to the container.
builder.Services.AddAuthorization();
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).
AddCookie(options =>
{
options.Cookie.Name = "auth_cookie";
options.LoginPath = "/";
options.LogoutPath = "/logout";
options.Cookie.MaxAge = TimeSpan.FromMinutes(90);
options.AccessDeniedPath = "/accessdenied";
});
builder.Services.ConfigureApplicationCookie(ops =>
{
ops.ExpireTimeSpan = TimeSpan.FromMinutes(30);
ops.SlidingExpiration = true;
}); builder.Services.AddCascadingAuthenticationState();
builder.Services.AddRazorComponents().AddInteractiveServerComponents();
builder.Services.AddScoped();
builder.Services.AddOutputCache();
builder.Services.AddSingleton();
builder.Services.AddBlazoredToast();
builder.Services
.AddBlazorise(options =>
{
options.Immediate = true;
})
.AddBootstrap5Providers()
.AddFontAwesomeIcons();
builder.Services.ConfigureApplicationCookie(ops =>
{
ops.ExpireTimeSpan = TimeSpan.FromMinutes(30);
ops.SlidingExpiration = true;
});
var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error", createScopeForErrors: true);
// 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.UseOutputCache();
app.MapRazorComponents().AddInteractiveServerRenderMode();
app.MapDefaultEndpoints();
app.Run();
Login.razor

Код: Выделить всё

@code {

async void Authenticate()
{
var result = await LoginApi.Login(login);

((CustomAuthStateProvider)AuthenticationStateProvider)
.AuthenticateUser(user.UserName, user.Role);
navigationManager.NavigateTo("/home");
}
}
MyAttribute.razor

Код: Выделить всё

@attribute [Authorize(Roles = "SuperAdmin")]
ОБНОВЛЕНИЕ

Итак, после многих попыток, У меня что-то частично работает. Он применяет атрибут Authorize, а также обновляет, но позволяет одновременно входить в систему в браузере только одному пользователю. Не проверял, разрешает ли он более одного входа в систему за пределами браузера - возможно, нет.
По сути, мне пришлось перехватить авторизацию и сверить ее с вошедшим в систему пользователем.
CustomAuthStateProvider.cs

Код: Выделить всё

using System.Security.Claims;
using Microsoft.AspNetCore.Components.Authorization;

namespace MyApp.Web.Utilities
{
public class CustomAuthStateProvider : AuthenticationStateProvider
{

private ClaimsIdentity _identity = new();
public override Task GetAuthenticationStateAsync()
{
var user = new ClaimsPrincipal(_identity);
return Task.FromResult(new AuthenticationState(user));
}

public void AuthenticateUser(string userIdentifier, string role)
{
_identity = new ClaimsIdentity(
[new Claim(ClaimTypes.Name, userIdentifier), new Claim(ClaimTypes.Role, role),], "Custom Authentication");
var user = new ClaimsPrincipal(_identity);

NotifyAuthenticationStateChanged(
Task.FromResult(new AuthenticationState(user)));
}

public async Task LogUserOut()
{
_identity = new ClaimsIdentity();
var user = new ClaimsPrincipal(_identity);
NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(user)));
}
}
}
CustomAuthorizationHandler.cs

Код: Выделить всё

using Microsoft.AspNetCore.Authorization.Policy;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components.Authorization;

namespace MyApp.Web.Utilities
{
public class CustomAuthorizationHandler : IAuthorizationMiddlewareResultHandler
{
private readonly AuthenticationStateProvider _authStateProvider;

public CustomAuthorizationHandler(AuthenticationStateProvider authStateProvider)
{
_authStateProvider = authStateProvider;
}
public Task HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult)
{
var result = _authStateProvider.GetAuthenticationStateAsync();
context.User = result.Result.User;
return next(context);
}
}
}
Program.cs

Код: Выделить всё

using Blazored.Toast;
using Blazorise;
using Blazorise.Bootstrap5;
using Blazorise.Icons.FontAwesome;
using MyApp.Web.APIClients;
using MyApp.Web.Components;
using MyApp.Web.Utilities;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components.Authorization;

// This is a Blazor Server Application (NOT a Webassembly App)
var builder = WebApplication.CreateBuilder(args);

// Add service defaults & Aspire components.
builder.AddServiceDefaults();

// Add services to the container.
builder.Services.AddAuthorization();
builder.Services.AddCascadingAuthenticationState();
builder.Services.AddRazorComponents().AddInteractiveServerComponents();
builder.Services.AddAuthorizationCore();
builder.Services.AddSingleton(); // To handle Authentication
builder.Services.AddScoped();
builder.Services.AddOutputCache();
builder.Services.AddBlazoredToast();
builder.Services
.AddBlazorise(options =>
{
options.Immediate = true;
})
.AddBootstrap5Providers()
.AddFontAwesomeIcons();
builder.Services.ConfigureApplicationCookie(ops =>
{
ops.ExpireTimeSpan = TimeSpan.FromMinutes(30);
ops.SlidingExpiration = true;
});
var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error", createScopeForErrors: true);
// 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.UseOutputCache();
app.MapRazorComponents().AddInteractiveServerRenderMode();
app.MapDefaultEndpoints();
app.Run();
Поэтому он в основном сохраняет аутентифицированного пользователя, а затем сравнивает его с запросом при вводе пути непосредственно в браузер. Я был бы рад этому решению, если бы оно поддерживало несколько пользователей, но это не так, поскольку это синглтон. Область видимости не сработала.

Подробнее здесь: https://stackoverflow.com/questions/791 ... r-not-work
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»