如何在 ASP.NET Core 3 的 Blazor 页面中正确重用具有授权的控制器

Ing*_*and 5 c# asp.net-web-api asp.net-core blazor blazor-server-side

先决条件:

  1. 单个 ASP.NET Core 3 Preview 8 项目,其中包括 Blazor 服务器端和 Web Api 控制器
  2. ASP.NET Core 身份
  3. 用于浏览器中以及从移动客户端调用 API 时的授权逻辑的 Cookie 和 JWT 令牌身份验证方案
  4. 为了简洁起见,此处的所有代码示例都具有最少量的代码。

这是初始 blazor 页面、模型和初始控制器

@page "/fetchdata"
@attribute [Authorize]
@using BlazorApp2.Controllers

<button @onclick="@callController">Call controller</button>

@code {
    private async Task callController()
    {
    }
}
Run Code Online (Sandbox Code Playgroud)
public class InputModel
{
    [Required]
    public string Message { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
[Route("api/[controller]")]
[ApiController]
[Authorize]
public class MessageController : ControllerBase
{
    [HttpPost("createMessage")]
    public async Task<ActionResult<string>> CreateMessage(InputModel model)
    {
        var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
        return $"{model.Message} {userId}";
    }
}
Run Code Online (Sandbox Code Playgroud)

以“正常”方式(通过发送 http 请求)使用控制器几乎没有什么内置好处:自动授权;模型验证;填充 HttpContext 和 User 属性(以及其他属性)。

目标是在获取 Blazor 页面数据时重用控制器。

想法1

配置控制器并将其注入 Blazor 页面,其操作的调用方式与 http 请求期间的调用方式类似。不确定如何实现这一点以及这是否确实可行。向 DI 容器注册控制器不是问题 ( AddControllersAsServices())。但这不会在注入期间填充控制器HttpContextUser属性。控制器注入后获得的唯一方法(我知道)是在( ) 中HttpContext配置并将其注入到控制器中。但这也意味着当使用http请求访问控制器时,可以从注入的属性和控制器的属性中访问。是否有可能因此出现问题?该解决方案也不会在控制器中进行模型验证。同时,可以在从 Blazor 页面发送之前验证模型,但我不确定在这种情况下是否必须在控制器中手动重新验证它。IHttpContextAccessorStartupservices.AddHttpContextAccessor();HttpContextIHttpContextAccessorHttpContext


[Route("api/[controller]")]
[ApiController]
[Authorize]
public class MessageController : ControllerBase
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public MessageController(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    [HttpPost("createMessage")]
    public async Task<ActionResult<string>> CreateMessage(InputModel model)
    {
        var userId = _httpContextAccessor.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
        return $"{model.Message} {userId}";
    }
}

Run Code Online (Sandbox Code Playgroud)
@page "/fetchdata"
@using BlazorApp2.Controllers
@attribute [Authorize]
@inject MessageController MessageController;

<button @onclick="@callController">Call controller</button>

@code {

    private async Task callController()
    {
        var result = (await MessageController
            .CreateMessage(new InputModel {Message = "Hello"})).Value;
    }
}
Run Code Online (Sandbox Code Playgroud)

想法2

使用 HttpClient 向控制器发出 http 请求。这里有2个问题。A) 不确定如何HttpClient在 DI 容器中注册,以便所有必需的身份验证 cookie 将自动添加到每次调用中;B) 从性能角度来看可能不是理想的解决方案,因为调用将离开服务器应用程序(在 blazor 页面中)并将返回到同一应用程序(在控制器中)。

走什么路?还有其他更好的办法吗?我的想法中错过了什么?