为什么我的 Authorize 属性只在客户端有效,在控制器中无效

问题描述 投票:0回答:0

我有一个包含客户端、服务器和共享项目的 Blazor WASM 项目。

问题

当我向我的控制器发出 Post 请求时,如果我添加

ActionResult
属性(即使我已登录),它也不想输入
[Authorize(Roles = "User")]
。但是,如果我添加
[AllowAnonymous]
属性,它就可以正常工作。

[HttpPost]
[Route("PostOutput")]
[Authorize(Roles = "User")]
public async Task<ActionResult<string>> PostOutput([FromBody] string json)
...

但是在客户端中,无论哪种方式都可以正常工作(只要我先登录)

<AuthorizeView>
    <NotAuthorized>
        @{
            navigationManager.NavigateTo("/login");
        }
    </NotAuthorized>
    <Authorized>
...

使用它可以访问页面,如果我像你期望的那样首先登录,当我将此属性添加到页面时它甚至可以工作

@attribute [Authorize(Roles = "User")]
。所以在客户端一切都按预期工作,但由于某种原因在服务器上没有。

我在这里错过了什么非常明显的东西吗?

项目设置

我设置客户端的方式是这样的

Program.cs(客户端)

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");

builder.Services.AddHttpClient<IAuthService, AuthService>(client =>
{
    client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress);
}).AddHttpMessageHandler<CustomAuthorizationHandler>();

builder.Services.AddHttpClient<IDashboardService, DashboardService>(client =>
{
    client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress);
}).AddHttpMessageHandler<CustomAuthorizationHandler>();

builder.Services.AddBlazoredSessionStorage();
builder.Services.AddTransient<CustomAuthorizationHandler>();
builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthenticationStateProvider>();
builder.Services.AddAuthorizationCore();
await builder.Build().RunAsync();

随着

CustomAuthorizationHandler
看起来像这样

public class CustomAuthorizationHandler : DelegatingHandler
{
    private ISessionStorageService _sessionStorageService;

    public CustomAuthorizationHandler(ISessionStorageService sessionStorageService)
    {
        _sessionStorageService = sessionStorageService;
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {

        var jwtToken = await _sessionStorageService.GetItemAsync<string>("UserSession");
        if (jwtToken != null)
        {
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", jwtToken);
        }

        return await base.SendAsync(request, cancellationToken);
    }

}

CustomAuthenticationStateProvider

public class CustomAuthenticationStateProvider : AuthenticationStateProvider
    {
        private readonly ISessionStorageService _sessionStorageService;
        private ClaimsPrincipal _anonymous = new ClaimsPrincipal(new ClaimsIdentity());

        public CustomAuthenticationStateProvider(ISessionStorageService sessionStorageService)
        {
            _sessionStorageService = sessionStorageService;
        }

        public override async Task<AuthenticationState> GetAuthenticationStateAsync()
        {
            try
            {
                var userSession = await _sessionStorageService.ReadEncryptedItemAsync<UserSessionModel>("UserSession");
                if (userSession == null)
                {
                    return await Task.FromResult(new AuthenticationState(_anonymous));
                }

                var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>
                {
                    new Claim(ClaimTypes.Name, userSession.Username),
                    new Claim(ClaimTypes.Role, userSession.Role)
                }, "JwtAuth"));

                return await Task.FromResult(new AuthenticationState(claimsPrincipal));
            }
            catch (Exception e)
            {
                return await Task.FromResult(new AuthenticationState(_anonymous));
            }
        }

        public async Task UpdateAuthenticationStateAsync(UserSessionModel userSession)
        {
            ClaimsPrincipal claimsPrincipal;
            if (userSession != null)
            {
                claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>
                {
                    new Claim(ClaimTypes.Name, userSession.Username),
                    new Claim(ClaimTypes.Role, userSession.Role)
                }));

                userSession.ExpireDateTime = DateTime.Now.AddSeconds(userSession.ExpiresIn);
                await _sessionStorageService.SaveItemEncryptedAsync("UserSession", userSession);
            }
            else
            {
                claimsPrincipal = _anonymous;
                await _sessionStorageService.RemoveItemAsync("UserSession");
            }

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

        public async Task<string> GetToken()
        {
            string result = String.Empty;

            try
            {
                var userSession = await _sessionStorageService.ReadEncryptedItemAsync<UserSessionModel>("UserSession");
                if (userSession != null && DateTime.Now < userSession.ExpireDateTime)
                {
                    result = userSession.Token;
                }
            }
            catch (Exception)
            {
            }
            return result;
        }

    }

SessionStorageServiceExtension.cs

public static class SessionStorageServiceExtension
{
    public static async Task SaveItemEncryptedAsync<T>(this ISessionStorageService sessionsStorageService, string key, T item)
    {
        var itemJson = JsonSerializer.Serialize(item);
        var itemJsonBytes = Encoding.UTF8.GetBytes(itemJson);
        var base64Json = Convert.ToBase64String(itemJsonBytes);
        await sessionsStorageService.SetItemAsync(key, base64Json);
    }

    public static async Task<T> ReadEncryptedItemAsync<T>(this ISessionStorageService sessionsStorageService, string key)
    {
        var base64String = await sessionsStorageService.GetItemAsync<string>(key);
        var itemJsonBytes = Convert.FromBase64String(base64String);
        var itemJson = Encoding.UTF8.GetString(itemJsonBytes);
        var item = JsonSerializer.Deserialize<T>(itemJson);
        return item;
    }
}

Program.cs(服务器)

var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("Default") ?? throw new NullReferenceException("No connection string in config!");
// Add services to the container.

builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();

builder.Services.AddAuthentication(o =>
{
    o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(o =>
{
    o.RequireHttpsMetadata = false;
    o.SaveToken = true;
    o.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuerSigningKey = true,
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(JwtAuthenticationManager.JWT_SECURITY_KEY)),
        ValidateIssuer = false,
        ValidateAudience = false
    };
});

builder.Services.AddSingleton<ProductService>();
builder.Services.AddTransient<UserAccountService>();
builder.Services.AddDbContextFactory<CoverAIDbContext>((DbContextOptionsBuilder options) => options.UseSqlServer(connectionString));
var app = builder.Build();
.net authentication blazor authorization blazor-webassembly
© www.soinside.com 2019 - 2024. All rights reserved.