观众无效错误
Posted
技术标签:
【中文标题】观众无效错误【英文标题】:The audience is invalid error 【发布时间】:2017-12-08 02:43:42 【问题描述】:我有 3 个项目 1- javascript SPA 2- Web API 项目,3- 带有 EF Core 的 IdentityServer
我开始调试 API 和 Identity Server 并成功获取 jwt 令牌,但是,当我尝试从具有授权属性的 API 方法中获取值时出现错误:
WWW-Authenticate →Bearer error="invalid_token", error_description="The audience is invalid"
我在身份验证选项中找不到任何有关观众的属性。这是我在 API 项目中的配置
app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
ApiSecret="secret",
Authority = "http://localhost:5000",
ApiName="fso.Api",
RequireHttpsMetadata = false,
);
还有我在 Identity 中的 Config.cs 文件
public class Config
public static IEnumerable<ApiResource> GetApiResources()
return new List<ApiResource>
new ApiResource()
Name = "fso.Api",
DisplayName = "feasion API",
Scopes =
new Scope("api1"),
new Scope(StandardScopes.OfflineAccess)
,
UserClaims =
JwtClaimTypes.Subject,
JwtClaimTypes.EmailVerified,
JwtClaimTypes.Email,
JwtClaimTypes.Name,
JwtClaimTypes.FamilyName,
JwtClaimTypes.PhoneNumber,
JwtClaimTypes.PhoneNumberVerified,
JwtClaimTypes.PreferredUserName,
JwtClaimTypes.Profile,
JwtClaimTypes.Picture,
JwtClaimTypes.Locale,
JwtClaimTypes.IdentityProvider,
JwtClaimTypes.BirthDate,
JwtClaimTypes.AuthenticationTime
;
public static List<IdentityResource> GetIdentityResources()
return new List<IdentityResource>
new IdentityResources.OpenId(),
new IdentityResources.Email(),
new IdentityResources.Profile(),
;
// client want to access resources (aka scopes)
public static IEnumerable<Client> GetClients()
return new List<Client>
new Client
ClientId = "fso.api",
AllowOfflineAccess=true,
ClientSecrets =
new Secret("secret".Sha256())
,
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
AllowedScopes =
StandardScopes.OfflineAccess,
"api1"
;
【问题讨论】:
【参考方案1】:请参阅 here 了解此声明的内容:
aud(受众)声明标识了 JWT 的目标接收者。打算处理 JWT 的每个主体都必须使用受众声明中的值来标识自己。如果存在此声明时,处理该声明的主体未使用 aud 声明中的值标识自己,则必须拒绝 JWT....
因此,您的 API 名称必须存在于 aud 声明中,以便 JWT 在由 API 中的中间件验证时有效。顺便说一句,您可以使用jwt.io 查看您的令牌,这有助于理解它。
为了让 IdentityServer 将您的 API 名称添加到 aud 声明中,您的客户端代码(尝试从 API 获取资源,因此需要访问令牌)应该从您的 API 请求范围。例如像这样(来自 MVC 客户端):
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
Authority = Configuration["IdpAuthorityAddress"],
ClientId = "my_web_ui_id",
Scope = "api1" ,
//other properties removed...
);
【讨论】:
jwt.io 链接有助于发现 -.net core 2.2
+ Microsoft.AspNetCore.Authentication.AzureAD.UI
clientId 值需要 api://
前缀。使用 .net core 3.1
+ microsoft.identity.web
它可以在没有 api://` 前缀的情况下工作。【参考方案2】:
为避免错误,应在 4 个位置一致地添加受众
-
在我的(例如 MVC)客户端中作为自定义范围。
在 API 应用程序中作为 ApiName
在 IdentityServer 客户端配置为 AllowedScope
在 API 资源配置中作为 ApiResource
查看详细信息(以前在 IdentityServer4 wiki 中可用):
在 identityServer4 中配置新的 API 连接时,会报错:
WWW-Authenticate: Bearer error="invalid_token",
error_description="The audience is invalid"
为避免错误,应在 4 个位置一致地添加 Audience
-
在我的(例如 MVC)客户端中作为自定义范围:
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
Authority = Configuration["IdpAuthorityAddress"],
ClientId = "my_web_ui_id",
Scope = "openid", "profile", "offline_access", "MyApi" ,
//other properties removed for brevity...
);
-
在 API 应用程序中作为 ApiName
//Microsoft.AspNetCore.Builder.IdentityServerAuthenticationOptions
var identityServerAuthenticationOptions = new IdentityServerAuthenticationOptions()
Authority = Configuration["Authentication:IdentityServer:Authority"],
RequireHttpsMetadata = false,
EnableCaching = false,
ApiName = "MyApi",
ApiSecret = "MyApiSecret"
;
-
在 IdentityServer \IdentityServerHost\Configuration\Clients.cs
(或数据库中相应的客户条目)
var client = new Client
ClientId = clientId,
//other properties removed for brevity...
AllowedScopes =
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
//IdentityServerConstants.StandardScopes.Email,
IdentityServerConstants.StandardScopes.OfflineAccess, "MyApi",
,
;
-
在 IdentityServer\IdentityServerHost\Configuration\Resources.cs(或数据库中对应的 ApiResource 条目)中作为 apiResource.Scopes
var apiResource = new ApiResource
Name = "MyApi",
ApiSecrets =
new Secret("MyApiSecret".Sha256())
,
UserClaims =
JwtClaimTypes.Name,
JwtClaimTypes.Profile,
,
;
【讨论】:
也许链接澄清了一切,但因为它似乎死了......我的理解是 dbo.ApiResources 中使用的名称应该与您的 API 中的 apiName 对齐,而您的客户端的命名范围必须对齐(a) dbo.ApiScopes 中列出的范围——它本身必须(通过 ApiResourceId)是 dbo.ApiResources 中资源的子级,以及 (b) dbo.ClientScopes 中的范围。也就是说,范围和资源名称need not be identical。我已经成功(并获得了理智)三个值,例如客户端的“Client”、资源的“ApiResource”和范围的“ApiScope”。 IdentityServer4 中有这么多 [错误] 选项,时间太短了 :) 这种逐步方法引导我找到所需的解决方案(将 API 名称与 IS 配置中的范围匹配)。如果他们不把所有东西都称为范围并将它们用于许多不同的用途! 我正在仔细检查您的(非常有帮助的)答案,并且在我分析内容对我的具体案例的影响时,我忍不住冒昧地编辑您的贡献(主要是突出显示和格式化)。我希望你不要介意。 (其实我希望你把它当作一种改进,并且乐于看到它。)【参考方案3】:在您的应用配置文件中的 AD 配置部分添加“Audience”行:
"AzureAd":
"Instance": "https://login.microsoftonline.com/",
"ClientId": "<-- Enter the Client Id -->",
"Audience": "<-- Enter the Client Id -->",
"TenantId": "<-- Enter the tenantId here -->"
在我的例子中,“ClientId”和“Audience”是一样的。
P.S.:如果在那之后你会看到
IDW10201:在不记名令牌中找不到范围或角色声明
在 AD 配置中添加另一行:
"AllowWebApiToBeAuthorizedByACL": true
更多here
【讨论】:
帮了我很多。谢谢!我必须对 Teams 应用程序进行身份验证(在团队之外运行时),我的听众就像api://<domain>/<client-id>
以上是关于观众无效错误的主要内容,如果未能解决你的问题,请参考以下文章
Azure AD 身份验证 401 错误“受众无效” AddAzureADBearer .Net Core Web Api