Azure AD 身份验证 401 错误“受众无效” AddAzureADBearer .Net Core Web Api

Posted

技术标签:

【中文标题】Azure AD 身份验证 401 错误“受众无效” AddAzureADBearer .Net Core Web Api【英文标题】:Azure AD Authentication 401 error "the audience is invalid" AddAzureADBearer .Net Core Web Api 【发布时间】:2020-03-11 02:39:15 【问题描述】:

我正在尝试创建一个简单的 Azure AD 身份验证示例using this sample,但我的客户端是 JQuery。当令牌显示观众为https://myportal.onmicrosoft.com/test_core_web_api_spa 时,我不确定为什么会收到关于观众无效的 401 错误。这与 Azure 中的 API 定义相匹配。唯一缺少的部分是 user_impersonation 的自定义范围,但是当我使用 MSAL clientApplication.acquireTokenSilent(tokenRequest2) 进行调用以获取令牌时,我的范围与 API 的完整 URL 与范围匹配:

const tokenRequest2 = 
    scopes: ["https://myportal.onmicrosoft.com/test_core_web_api_spa/user_impersonation"]
;

在建立身份验证的 API 中我正在使用此代码(我注意到使用此方法的示例并不多)

services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
   .AddAzureADBearer(options => Configuration.Bind("AzureAd", options));

API 的配置是

  "AzureAd": 
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "myportal.onmicrosoft.com",
    "TenantId": "my-tenant-guid",
    "ClientId": "my-api-client-guid"
  ,

我注意到许多示例显示了 API 的不同格式(我假设这些是旧版本),但暴露的 API 范围在 Azure 中列为https://myportal.onmicrosoft.com/test_core_web_api_spa/user_impersonation。我还使用 Azure 仪表板添加了客户端的 guid,以访问这个公开的 API 范围。

任何想法我哪里出错了?或者,任何使用 MSAL、JQuery 客户端和简单的 .Net Core Web Api 的简单示例?似乎我发现的所有示例都已过时或使用不同的客户端或不同的身份验证方法。

更新以在 Azure 中为 web api 应用程序显示公开 api 设置。 我从 Azure 添加了一张图片,显示了“公开 api”屏幕的设置。我添加了自定义范围user_impersonation,然后添加了客户端并授予它对该范围的访问权限。如您所见,我的 Azure 订阅没有其他人看到的 api://guid 格式。当我尝试使用 api://guid 格式时,我收到错误 The resource principal named api://guid was not found in the tenant

我还添加了令牌的图像。 aud 标记与我在 Azure 中的 Web api 应用程序名称相匹配。 scp 列出了我附加到我的范围请求的范围。我只是看不出还有什么可以尝试的。

【问题讨论】:

您应该检查的一件事是令牌中的 aud 声明是什么?是您的 API 应用 ID URI 还是 API 客户端 ID? @juunas aud 声称令牌与 Azure 门户中公开的 API 匹配。我在第二句中列出了它,然后在结尾处引用了定义。 【参考方案1】:

范围不正确,这就是你得到the audience is invalid的原因。

范围应该类似于api://web_api_clientId/read

【讨论】:

范围不能正确。我已经多次使用过这种应用 ID URI。 @Tony Ju - Azure 门户中没有任何与您的范围相似的内容。我看到的任何地方都没有以 API:// 开头。我真的很困惑为什么我们在门户网站上有如此不同的观点。可能是因为我的是公司帐户?【参考方案2】:

问题在于 Web API 的配置数据。当他们说ClientId 时,他们真正想要的是“公开 API”选项下的值,其中显示“应用程序 ID URI”。我放在那里的是 Web Api 应用程序注册的指南。下面是它的外观。

  "AzureAd": 
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "myportal.onmicrosoft.com",
    "TenantId": "mytenant-guid",
    "ClientId": "https://myportal.onmicrosoft.com/test_core_web_api_spa"
  ,

API 格式说明。 看来,当您直接在 Azure 中注册应用程序时,公开 API 的格式将是 api://app-guid。但是,如果您首先使用 Visual Studio 创建应用程序,则格式将默认为 https:///myportal.onmicrosoft.com/project-name-in-visual-studio

【讨论】:

如果我能投票一百万次,我会的。我浪费了整整 2 天的时间来解决这个问题。非常不负责任的属性命名和糟糕的文档。 可笑的是,如果您遵循“创建 ASP.NET Core Web 应用程序”向导,您最终会得到一个 appsettings.json,其中 ClientId(=^ GUID),而不是应用程序ID URI(=^ URI,见上)为“ClientId”填写——配置值。 我整天都在拉头发看着 GUID!谢谢!!!【参考方案3】:

不要只看下面的代码,请阅读!

根据 pretzelb 所说的,不必太担心您的客户端是如何配置的(只要您的客户端正常工作)。假设您收到的错误与无效的发行者或无效的受众有关,请尝试以下操作。

在您的客户端尝试连接并查看HttpContext - Request - Headers - Values 后调试您的 api 并在某处设置调试点,在那里您将看到您的令牌,因此将其放入 jwt io 网站,您应该找到您的发行者和您的受众可能与您预期的完全不同。此时更改您的 TokenValidationParameters 以与您在令牌中找到的内容一致,然后它应该可以工作。

使用 .Net Core 3.1 和 Micorosft.Identity.Web(目前为预览版),我将向您展示什么对我有用:

这是我的假 guid 配置。不要尝试使用相同的实例,您需要查看客户端发送的令牌中的颁发者。

"AzureAD": 
    "Instance": "https://sts.windows.net/",
    "ClientId": "28e36e14-5191-4987-bcdf-982d958de2b3",
    "Domain": "funco.com",
    "TenantId": "744ce43f-a10f-499f-29f3-7je6ef439787"
  

在某处为 AzureAd 配置部分创建一个模型:

public class AzureModel
    
        public String Instance  get; set; 
        public String ClientId  get; set; 
        public String Domain  get; set; 
        public String TenantId  get; set; 
    

那么……

services.AddProtectedWebApi(Configuration, AzureADDefaults.AuthenticationScheme,  AzureADDefaults.JwtBearerAuthenticationScheme);
services.Configure<JwtBearerOptions>(AzureADDefaults.JwtBearerAuthenticationScheme, options =>

    var azureSettings = Configuration.GetSection(AzureADDefaults.AuthenticationScheme).Get<AzureModel>();
    options.TokenValidationParameters = new TokenValidationParameters
    
        ValidateIssuerSigningKey = true,
        ValidateIssuer = true,
        ValidIssuer = $"azureSettings.InstanceazureSettings.TenantId/",
        ValidateAudience = true,
        ValidAudience = $"https://azureSettings.Domain/azureSettings.ClientId",
        //ValidateLifetime = true,
        //ClockSkew = TimeSpan.Zero
    ;

    options.Events = new JwtBearerEvents();

    options.Events.OnTokenValidated = async context =>
    
            await Task.FromResult(0);
    ;
    options.Events.OnAuthenticationFailed = async context =>
    
        await Task.CompletedTask;
    ;
    options.Events.OnMessageReceived = async context =>
    
        await Task.CompletedTask;
    ;
);

【讨论】:

【参考方案4】:

像这里的大多数人一样,我在此问题上停留了一段时间,文档严重让它失望了。

按照 MS 指南,它会像这样在服务器项目中填充 appsettings 文件

"AzureAd": 
"Instance": "https://login.microsoftonline.com/",
"Domain": "contoso.onmicrosoft.com",
"TenantId": "e86c78e2-8bb4-4c41-aefd-918e0565a45e",
"ClientId": "41451fa7-82d9-4673-8fa5-69eff5a761fd",
 

令人沮丧的是,此修复方法非常简单,只需使用 api:// 预先修复客户端 ID,以便它与 JWT 中的受众和 AAD 中公开服务器应用程序的 API 部分中的应用程序 ID URI 匹配

"AzureAd": 
"Instance": "https://login.microsoftonline.com/",
"Domain": "contoso.onmicrosoft.com",
"TenantId": "e86c78e2-8bb4-4c41-aefd-918e0565a45e",
"ClientId": "api://41451fa7-82d9-4673-8fa5-69eff5a761fd",
 

【讨论】:

.net core 2.2 + Microsoft.AspNetCore.Authentication.AzureAD.UI clientId 值需要api:// 前缀。使用 .net core 3.1 + microsoft.identity.web 它可以在没有 api://` 前缀的情况下工作。 我上面描述的示例是使用 .net core 3.1 使用 Blazor WASM 模板完成的。这里的关键是clientId需要匹配Azure ADD app API中设置的Application ID URI【参考方案5】:
const tokenRequest2 = 
    scopes: ["test_core_web_api_spa/user_impersonation"]
;

const tokenRequest2 = 
    scopes: ["app-guid/user_impersonation"]
;

当您的应用程序需要为资源 API 请求具有特定权限的访问令牌时,以 / 格式传递包含 API 的应用 ID URI 的范围。

不同资源的一些示例范围值:

Microsoft Graph API:https://graph.microsoft.com/User.Read 自定义网页 API:api://11111111-1111-1111-1111-111111111111/api.read 范围值的格式取决于接收访问令牌的资源(API)及其接受的 aud 声明值。

仅对于 Microsoft Graph,user.read 范围映射到 https://graph.microsoft.com/User.Read,两种范围格式可以互换使用。

Azure 资源管理器 API (https://management.core.windows.net/) 等某些 Web API 需要在访问令牌的受众声明 (aud) 中使用尾部正斜杠 ('/')。在这种情况下,将范围传递为 https://management.core.windows.net//user_impersonation,包括双斜杠 ('//')。

其他 API 可能要求范围值中不包含任何方案或主机,并且只需要应用 ID(GUID)和范围名称,例如:

11111111-1111-1111-1111-111111111111/api.read

参考号:https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-acquire-cache-tokens

使用https://jwt.ms/ 解码您的令牌

【讨论】:

以上是关于Azure AD 身份验证 401 错误“受众无效” AddAzureADBearer .Net Core Web Api的主要内容,如果未能解决你的问题,请参考以下文章

401 使用 Azure AD 在 .NET Core 3.1 中仅使用不记名令牌进行身份验证

通过邮递员从 Azure 应用服务验证令牌返回 401

Azure AD - HTTP/1.1 401 未经授权 - Windows 服务

Hashicorp Vault OIDC 身份验证方法与 Azure AD 错误验证签名

Azure AD:50155 设备身份验证失败

Xamarin Azure AD 身份验证需要管理员权限