Web api 的 AAD 客户端凭据流请求范围
我有一个控制台应用程序,需要支持两个流程,针对 AAD 进行身份验证以与 Web api 对话:
- 对于人类的常规使用,它需要支持交互式登录,
- 以供 CI/CD 管道使用,它需要支持客户端凭据。
交互流程工作完美,但客户端凭据流程给我带来了请求范围的问题。
我正在使用最新的 Microsoft.Identity*
nuget 包。
当我像交互流那样构建 webapi 的范围时,我收到一条错误消息,告诉我对于客户端凭据流,我需要附加 ./default
。好吧,公平地说,我还发现 文档为此,所以我附加 ./default
。但是当我这样做时,我收到另一条错误消息告诉我
在名为 的租户中找不到名为 api:///access_as_user 的资源主体。
此错误消息有两个问题:
- 引用的资源主体肯定存在 - 另外,如果不存在,我将无法交互式登录,但正如前面提到的,交互式登录工作得很好,
- 它说
api://< webApiAppId>/access_as_user
,而不是api://
,尽管我附加了/access_as_user/.default
我的下一个:嗯,也许问题是应用程序用于客户端凭据流的注册没有 web-api 的权限。但确实如此。
所以现在我已经没有想法了。希望这里有人可以提供帮助。
为了让一切变得更清晰,让我列出所涉及的应用程序注册:
A. Web Api
- 是通过 VS Wizard/dotnet-msidentity 工具设置的
- ,定义了一些应用程序角色,
- 公开了单个 API
api://
;/access_as_user
B. 交互式登录
- 创建
- 重定向 URI
- 手动为本地主机API 权限 :添加了
WebApi | access_as_user
作为委托
非交互式登录/服务主体
- 设置
- C. CI/CD 管道手动
- 也可用于其他用途,具有 ClientSecret 定义的
- API 权限:添加了 WebApi | access_as_user 。 access_as_user 为 A 定义了 2 个应用程序角色,
- 具有与此处无关的其他 API 权限(对于图)
- 授予管理员对所有权限的同意
我用于身份验证的代码是(对于机密流程):
ConfidentialClientApplicationBuilder.Create(_configuration.ApplicationId)
.WithTenantId(_configuration.Directory)
.WithLogging(Log, LogLevel.Error)
.WithClientSecret(_configuration.ClientSecret)
.Build()
.AcquireTokenForClient(_configuration.Scopes)
.ExecuteAsync();
其中 _configuration
的值为:
ApplicationId
:应用注册中的 appId CDirectory
:我的 AAD 租户的名称ClientSecret:秘密来自应用程序注册 C
Scopes
:openid
、profile
和api://
的数组代码>/access_as_user/.default
I got a console app that needs to support two flows, authenticating against AAD to talk to a web api:
- for regular usage by humans, it needs to support interactive login
- for usage by a CI/CD pipeline it needs to support client-credentials.
The interactive flow works perfectly, but the client-credentials flow is giving me problems with the requested scope.
I'm using the latest Microsoft.Identity*
nuget packages.
When I construct the scope for the webapi like I do for the interactive flow, I get an error message telling me that for client-credentials flows I need to append ./default
. Okay, fair enough, I also found documentation for this, so I append ./default
. But when I do that, I get another error message telling me
The resource principal named api:///access_as_user was not found in the tenant named .
There are two problems with this error message:
- the resource principal quoted definitely exists - also, I couldn't login interactively if it didn't, but as mentioned, interactive login works just fine
- it says
api://<webApiAppId>/access_as_user
, notapi://<webApiAppId>/access_as_user/.default
, despite my appending that
My next though was: well, maybe the problem is that the app registration used for the client-credentials flow doesn't have permissions on the web-api. But it does.
So now I've run out of ideas. Hopefully, someone here can help.
To make everything a bit clearer, let me list the app regs involved:
A. Web Api
- Was setup via the VS Wizard/dotnet-msidentity tool
- has a few App Roles defined
- exposes a single API
api://<itsownAppId>/access_as_user
B. Interactive Login
- manually created
- redirect URI for localhost
- API Permissions: added
WebApi | access_as_user
as delegated
C. Non-interactive login/Service Principal
- setup manually
- is used also for other things by the CI/CD pipeline
- has a ClientSecret defined
- API Permissions: added
WebApi | access_as_user
with 2 of the app roles defined for A - has other API Permissions that have nothing to do with this here (for Graph)
- granted admin consent for all permissions
The code I use to authenticate is (for the confidential flow):
ConfidentialClientApplicationBuilder.Create(_configuration.ApplicationId)
.WithTenantId(_configuration.Directory)
.WithLogging(Log, LogLevel.Error)
.WithClientSecret(_configuration.ClientSecret)
.Build()
.AcquireTokenForClient(_configuration.Scopes)
.ExecuteAsync();
where the values of _configuration
are:
ApplicationId
: the appId from app registration CDirectory
: the name of my AAD tenantClientSecret
: the secret from app registration CScopes
: array ofopenid
,profile
andapi://<appIdOfWebApiFromC>/access_as_user/.default
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
因此,事实证明,附加
./default
的文档不够清晰:您并不打算将其附加到作用域,而只是将其附加到“资源 id”。对于资源 ID,它们意味着“api://”部分不权限名称。因此,在您通常请求
api:///access_as_user
的地方,对于客户端凭据流程,您必须请求api:///.default
So, it turns out that the documentation for appending
./default
is not quite clear enough:.You are not meant to append it to the scope, just to the "resource id". And with resource id they mean the "api://" parts without the name of the permission.So where you normally request
api://<webApiAppId>/access_as_user
, for the client-credentials flow you have to requestapi://<webApiAppId>/.default