同一 ASP.NET 核心 API 中的 Azure AD 客户端凭据和交互

Azure AD Client Credentials and Interactive in same ASP.NET Core API

我有一个 ASP.NET Core (3.1) web API 和几个客户端 UI 应用程序。通过 Azure AD 进行身份验证,一切正常,使用:

services.AddAuthentication()
    .AddAzureADBearer(options => Configuration.Bind("AzureAD", options))

我还想使用客户端凭据流程允许机器对机器 API 访问。我也可以使用相同的应用程序注册使它正常工作。

但是,我需要一种方法来验证请求正在使用哪个流,因为我想使用客户端凭据 API 向 API 请求公开我不希望交互式用户使用的功能可以访问。

完成这项工作的最佳方法是什么?

我在 AAD 中创建了一个单独的应用程序注册,客户端凭据授予的客户端密码已打开,我让它向令牌添加权限(作为角色)。在 API 的应用程序注册中,我已授予客户端凭据应用程序注册权限。但是,如果我通过此流程获得令牌,则无法进行身份验证。我发现更改令牌请求中的范围以匹配 API 应用程序注册的范围会给我一个允许我访问 API 的令牌,但它会丢失应用程序角色。

一个交互式令牌有一些用户特定的声明。因此,一种解决方法是检查这些声明是否存在,如果它们存在,则禁止我想要限制的功能,但这似乎有点老套。

我还能做什么?有没有办法使两个登录流程都有效?或者我错过的另一个选择?

万一其他人需要让它工作,我通过切换来让它工作:

services.AddAuthentication()
    .AddAzureADBearer(options => Configuration.Bind("AzureAD", options))

至:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.MetadataAddress = $"https://login.microsoftonline.com/mydomain.onmicrosoft.com/.well-known/openid-configuration";
        options.TokenValidationParameters.ValidateAudience = false;
    });

如问题中所述,还有一些额外的步骤。我在 AAD 中创建了一个单独的应用程序注册,并在应用程序注册中为 API 授予了新应用程序注册的权限。在新的应用程序注册中,我必须编辑清单以获得我想要作为角色包含的范围(范围仅分配给用户令牌,而不是通过客户端凭据授予获得的令牌)。

使用具有角色数据的令牌,对于对我的受限端点的请求,我可以检查它是否存在:

public bool ValidateScope(string scopeName)
{
    return _httpContextAccessor.HttpContext.User.IsInRole(scopeName);
}

bool authorised = _clientCredentialsService.ValidateScope("restricted");

if (!authorised)
{
    throw new UnauthorizedAccessException("Attempt to access restricted functionality as a regular user");
}

(我有一个过滤器可以检测到这个异常并将其作为 403 冒泡给消费者)。

如果其他人正在这样做,您可以看到我已将 ValidateAudience 设置为 false,因此如果您这样做,您可能想要添加一些政策。