首页 > 解决方案 > 如何向已经使用 Identity 的 MVC 控制器添加 API 身份验证和授权?

问题描述

语境

我有一个带有多个控制器的 ASP.NET Core MVC 应用程序(仅返回视图)。该应用已使用 ASP.NET Core Identity 进行身份验证和授权。但是,有几个地方我需要使用 HTTP 客户端直接调用控制器操作端点作为 API。这似乎需要 Identity 似乎不支持开箱即用的 API 身份验证。


问题

我需要使用组件标签助手(渲染模式为)从嵌入到我的 MVC 视图中的 Razor 组件调用这些控制器操作ServerPrerendered

现在,我可以直接从我的 Razor 组件访问我的数据库,方法是将数据库服务注入到我的组件中,就像我为其他 Razor 组件所做的那样。但是,我不能用这个 Razor 组件来做到这一点,因为它需要访问UserManagerIdentity 服务并且根据文档

SignInManager<TUser>并且UserManager<TUser>在 Razor 组件中不受支持。Blazor 服务器应用使用 ASP.NET Core 标识。

因此,似乎我可能不得不通过注入从我的 Razor 组件调用控制器操作IHttpClientFactory。但是,到目前为止,在我的整个应用程序中,我只需要为两个操作调用控制器操作:

您可能会问为什么我需要 Razor 组件来创建用户帐户。创建帐户是一个相当复杂的步骤(多个步骤),涉及客户端交互,例如将项目动态添加到列表中。Razor 组件让我变得如此简单。.cshtml如果我在视图中执行此操作,我将不得不使用 JavaScript/jQuery 。


目标

我不认为仅仅为了帮助我完成这两个操作而创建一个完整的 API 项目是值得的(尽管我不介意这样做)。我可以将这些操作添加到我现有的帐户控制器或在同一个项目中创建一个新的 API 控制器。尽管如此,我仍然必须保护这些端点

主要问题

如何向这两个控制器操作(创建用户和编辑用户)添加 API 身份验证和授权,而不干扰现有的 ASP.NET Core 身份设置正在做什么?

我仍然希望我的应用程序中的其余控制器具有相同的身份验证/授权,但这些CreateEdit用户操作的 API 身份验证/授权。

或者由于我的 Razor 组件嵌入在 MVC 视图中,有没有办法通过我的组件调用控制器操作,就像 MVC 视图通过发送带有请求的 cookie 一样?

无论哪种方式,我的目标是保护两个控制器操作端点。


代码

这是身份当前配置的方式Startup.cs

 services.AddDefaultIdentity<AppUser>()
                .AddRoles<IdentityRole>()
                .AddEntityFrameworkStores<AppDbContext>();

这是我的Create控制器操作的简化版本:

[Authorize(Roles = "Administrator")]
public async Task<IActionResult> Create(UserViewModel model) 
{
    if (ModelState.IsValid)
    {
        AppUser user = model.ToAppUser(); // Method on view model does the mapping
        user.Id = Guid.NewGuid().ToString();
        IdentityResult createUserResult = await _userManager.CreateAsync(user, model.Password);
        if (createUserResult.Succeeded)
        {
            await userManager.AddToRoleAsync(user, role.Name);
            return Ok();
        }
        foreach(var error in createUserResult.Errors) 
        {
            ModelState.AddModelError("", error.Description);
        } 
    }
}

这就是我从 Razor 组件调用它的方式:

CreateUser.razor

@inject IHttpClientFactory HttpClientFactory

<EditForm Model="_model" OnValidSubmit="HandleValidSubmit">
    ...
</EditForm>

@code {
    private UserViewModel _model = new();

    public async Task HandleValidSubmit()
    {
        var modelAsJson = new StringContent(
            JsonSerializer.Serialize(_model),
            Encoding.UTF8,
            "application/json");

        using var httpResponse =
            await _httpClient.PostAsync("/api/Accounts/Create", modelAsJson);
        //...
    }
}

使用以下方法将组件嵌入到 MVC 视图中<component>

Create.cshtml

...
<component type="typeof(CreateUser)" render-mode="ServerPrerendered" />

更新

经过一番研究,我发现 JWT 是最常用的 API 身份验证方式。根据此处的说明,它是这样添加的Startup.cs

services.AddAuthentication( auth =>
{
    auth.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    auth.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options => {..})

在这里,当默认身份验证方案设置为 JWT 时,这会覆盖我的默认身份设置吗?如何同时使用这两种方案?

标签: c#asp.netasp.net-coreauthenticationblazor

解决方案


有一种方法可以在 asp.net 核心中支持多种身份验证方案。

它看起来像这样:

启动类

public void ConfigureServices(IServiceCollection services)
{
   serviced.AddDefaultIdentity<AppUser>()
                  .AddRoles<IdentityUser>()
                  .AddEntityFrameworkStores<AppDbContext>();

   services.AddAuthentication()
       .AddCookie(options => {
           options.LoginPath = "/Account/Unathorized/"
           options.AddAccessDeniedPath = "/Account/Forbidden"
        });
}

控制器

[Authorize(AuthenticationSchemes = YourCustomeScheme)]
public class AuthController: controller 

您可以根据需要添加和使用任意数量的方案。


推荐阅读