我正在学习如何为 OAuth 服务生成 token ,它将在聊天机器人中使用。当我使用下面显示的代码时,我可以成功获取默认范围的 Graph token ,并且该 token 对于 MS Graph API 调用有效。现在,我想要实现的是以类似的方式生成自定义范围 token ,以便调用外部服务(不是 MS Graph API)。该 token 需要具有自定义范围。我尝试将字典参数“范围”更改为为 Azure 中的聊天机器人配置的范围名称,但失败了:
private async Task<string> GetGraphTokenAsync()
{
var dict = new Dictionary<string, string>();
dict.Add("client_id", _graphTokenSettings.ClientId);
dict.Add("client_secret", _graphTokenSettings.ClientSecret);
dict.Add("scope", "https://graph.microsoft.com/.default");
dict.Add("grant_type", "client_credentials");
string gUrl = $"https://login.microsoftonline.com/{_graphTokenSettings.Tenant}/oauth2/v2.0/token";
var client = new HttpClient();
var req = new HttpRequestMessage(HttpMethod.Post, gUrl) { Content = new FormUrlEncodedContent(dict) };
var httpResponseFromService = await client.SendAsync(req);
httpResponseFromService.EnsureSuccessStatusCode();
if (httpResponseFromService.Content is object
&& httpResponseFromService.Content.Headers.ContentType.MediaType == "application/json")
{
string stringFromservice = await httpResponseFromService.Content.ReadAsStringAsync();
JObject tokenresponse = JsonConvert.DeserializeObject<JObject>(stringFromservice);
string token = tokenresponse["access_token"].Value<string>();
return token;
}
else
{
_logger.LogError($"Cannot get token for Microsoft Graph. httpResponseFromService.Content:{httpResponseFromService.Content}" );
throw new Exception("Cannot get token for Microsoft Graph.");
}
}
我的机器人中的提供程序配置如下,它是否用作服务提供程序:Azure Active Directory v2:
这是使用 OAuth 工具生成的自定义 token 的示例(租户 ID 和其他值更改为仅说明数据,但所有这些值在使用时都匹配且正确),它正在调用相同的 url我尝试调用“login.microsoftonline.com”来生成自定义范围 token :
此生成的自定义范围 token 有效。它已在我的租户 Azure 级别配置为“api://botid-GUID/access_as_user”,但我想通过 http 客户端生成它作为我的代码示例。您知道如何使用此自定义范围和类似的 httpClient 方法获取 token 吗?看来我发送的范围参数(“api://botid-GUID/access_as_user”)对于 client_credentials 授予类型调用不正确:
默认范围:
dict.Add("client_id", _graphTokenSettings.ClientId);
dict.Add("client_secret", _graphTokenSettings.ClientSecret);
dict.Add("scope", "https://graph.microsoft.com/.default");
dict.Add("grant_type", "client_credentials");
替换为:
dict.Add("client_id", _graphTokenSettings.ClientId);
dict.Add("client_secret", _graphTokenSettings.ClientSecret);
dict.Add("scope", "api://botid-GUID/access_as_user");
dict.Add("grant_type", "client_credentials");
任何帮助将不胜感激。
最佳答案
我尝试在我的环境中重现相同的结果并得到以下结果:
我有一个 Azure AD 应用程序,通过公开 API 创建了一个自定义范围,如下所示:
我注册了另一个名为 ClientApp
的应用程序,并通过授予同意将其添加到自定义范围之上,如下所示:
在我的 Azure 机器人中,我添加了一项与服务提供商的连接设置作为 Azure Active Directory v2,如下所示:
当我运行测试连接
时,我成功获得了 token ,如下所示:
当我解码上述 token 时,我得到了范围如下的声明:
当您通过公开 API 创建自定义范围时,它会受到涉及用户交互的委派权限的控制,如下所示:
Note that, client credential flow only works with Application permissions that does not involve user interaction.
您需要创建应用角色
,而不是在具有不同唯一值访问权限的应用程序中公开 API-作为用户
如下所示:
您可以将上述应用角色
添加到应用程序权限下的客户端应用程序中,并确保授予同意,如下所示:
除此之外,客户端凭据授予类型支持在使用 v2 端点时仅以 /.default
结尾的范围。否则,它将抛出异常,如下所示:
要解决上述错误,您需要在end处将范围替换为/.default
,如下所示生成 token 时:
POST https://login.microsoftonline.com/<tenantID>/oauth2/v2.0/token
client_id:appID
grant_type:client_credentials
client_secret:secret
scope: api://87xxxa-6xex-4dxa-9xaf-b1dxxxx9819/.default
回应:
当我解码上述 token 时,我得到了具有以下角色的声明:
请注意,解码后的 token 在roles
声明中包含Application权限,而在scp
声明。
在您的场景中,如果您想要将自定义范围与客户端凭据授予类型一起使用,则需要创建具有唯一值的应用角色
属于应用程序权限。
确保在结束处使用/.default
更改范围。
关于Azure Active Directory v2 - 获取自定义范围 token ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74441243/