Blazor 8 中的 Cookie 身份验证具有个人帐户作为身份验证,不适用于 API 控制器

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

我通过选择渲染模式“自动(服务器和 WebAssembly)”并使用“个人帐户”作为身份验证创建了 Blazor 8 应用程序。该应用程序在“管理员”和“用户”等各种角色下运行良好。

Blazor 服务器项目中还有一个 API 控制器,它也使用 Authorize 属性进行修饰。 Blazor 客户端应用程序正在使用 HttpClient 调用 API。如果 API 控制器上没有 Authorize 属性,Blazor 客户端应用程序可以获取数据,但当我使用 Authorize 属性时,它无法调用 API。  相同的身份验证方案如何与 API 控制器配合使用?如何使 API 可从 Blazor 客户端应用程序成功调用?

服务器项目中的Program.cs如下:

using BlazorAppAuthenticationDemo.Client.Services;
using BlazorAppAuthenticationDemo.Components;
using BlazorAppAuthenticationDemo.Components.Account;
using BlazorAppAuthenticationDemo.Data;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddScoped<TemplateService>();
builder.Services.AddControllers();

builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents()
    .AddInteractiveWebAssemblyComponents();

builder.Services.AddCascadingAuthenticationState();
builder.Services.AddScoped<IdentityUserAccessor>();
builder.Services.AddScoped<IdentityRedirectManager>();
builder.Services.AddScoped<AuthenticationStateProvider, PersistingRevalidatingAuthenticationStateProvider>();

builder.Services.AddAuthentication(options =>
    {
        options.DefaultScheme = IdentityConstants.ApplicationScheme;
        options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
    })
    .AddIdentityCookies();

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddIdentityCore<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddRoles<IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddSignInManager()
    .AddDefaultTokenProviders();

builder.Services.AddSingleton<IEmailSender<ApplicationUser>, IdentityNoOpEmailSender>();

builder.Services.AddScoped(http => new HttpClient
{
    BaseAddress = new Uri(builder.Configuration.GetSection("BaseAddress").Value!)
});

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseWebAssemblyDebugging();
    app.UseMigrationsEndPoint();
}
else
{
    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.MapControllers();
app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode()
    .AddInteractiveWebAssemblyRenderMode()
    .AddAdditionalAssemblies(typeof(BlazorAppAuthenticationDemo.Client._Imports).Assembly);

// Add additional endpoints required by the Identity /Account Razor components.
app.MapAdditionalIdentityEndpoints();

app.Run();

客户端项目中的Program.cs如下:

using BlazorAppAuthenticationDemo.Client;
using BlazorAppAuthenticationDemo.Client.Services;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;

var builder = WebAssemblyHostBuilder.CreateDefault(args);

builder.Services.AddAuthorizationCore();
builder.Services.AddCascadingAuthenticationState();
builder.Services.AddSingleton<AuthenticationStateProvider, PersistentAuthenticationStateProvider>();

builder.Services.AddScoped<TemplateService>();

builder.Services.AddScoped(http => new HttpClient
{
    BaseAddress = new Uri(builder.HostEnvironment.BaseAddress),
});

await builder.Build().RunAsync();

TemplateService.cs 来使用 API:

using BlazorAppAuthenticationDemo.Shared.Models;
using System.Net.Http.Json;

namespace BlazorAppAuthenticationDemo.Client.Services;

public class TemplateService(HttpClient httpClient)
{
    private readonly HttpClient _httpClient = httpClient;

    public async Task<List<TemplateDTO>?> All()
    {
        var templates = await _httpClient.GetAsync($"api/Templates/all");

        List<TemplateDTO>? data = null;

        if (templates.IsSuccessStatusCode)
        {
            data = await templates.Content.ReadFromJsonAsync<List<TemplateDTO>?>();
        }
        return data;
    }
}

TemplatesController.cs 有一个端点:

using BlazorAppAuthenticationDemo.Shared.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace BlazorAppAuthenticationDemo.Controllers;

[Route("api/[controller]")]
[ApiController]
public class TemplatesController : ControllerBase
{
    private readonly List<TemplateDTO> _templates = [
        new TemplateDTO {Id =1, Name = "Test 1", Content = "This is first template." },
        new TemplateDTO { Id =2, Name = "Test 2", Content = "This is second template."},
        new TemplateDTO { Id =3, Name = "Test 3", Content = "This is third template."}
        ];

    [HttpGet("all")]
    [Authorize(Roles = "Administrators")]
    public async Task<ActionResult<List<TemplateDTO>>> All()
    {
        await Task.CompletedTask;

        return Ok(_templates);
    }
}
.net-core blazor blazor-server-side blazor-webassembly
1个回答
0
投票

在你的服务器程序.cs中注册控制器,以确保路由能够被正确识别。

...
builder.Services.AddControllers();

var app = builder.Build();
...
app.MapControllers();

app.Run();

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.