使用不记名令牌使用 AutoRest C# 客户端访问 Web API - TokenCredentials 不起作用
Using an AutoRest C# client to access a Web API with a bearer token - TokenCredentials does not work
编辑 10/24
我认为这很可能是用户错误 - 在深入探讨这个问题之前,请参阅下面的答案以寻求补救措施
TL;DR:
对于我的 OAuth 2.0 代码流...
Why does my TokenCredentials
not work with my AutoRest client?
I'm getting NO bearer token applied to the request / no Authorization header set
我知道我的管道已经工作了..
使用来自 this azure sample 的代码,它不是 AutoRest 客户端,我可以成功地获取我的 access_token
并且可以从我的受保护的 Web API 项目中获取 JSON。 .所以我排除了所有先决条件..我知道我的管道有效
我的 AutoRest 设置..
1.) 下载自 GitHub this AutoRest repo v1.1.0
2.) 下载我的 swagger JSON 到磁盘,保存为 swagger.json
3.) 运行 这个 command-line 生成 C# 文件:
autorest --input-file=swagger.json --csharp --output-folder=MyCorp_ApiClient_Tsl --namespace='MyCorp.ApiClient' --add-credentials
4.) 将生成的 类 复制到我的 .NET 4.6.2 网站
5.) 这些是我的 NuGet:
- Microsoft.Rest.ClientRuntime version="2.3.8"
- Microsoft.Rest.ClientRuntime.Azure.Authentication version="2.3.1"
- Microsoft.IdentityModel.Clients.ActiveDirectory version="2.28.3"
这是不起作用的地方:
AdalTokenHelper tokenHelper = new AdalTokenHelper();//helper code further below
string token = await tokenHelper.GetTokenString();
var svcClientCreds = new TokenCredentials(token, "Bearer");
client = new MyCorp.ApiClient(new Uri(apiRsrcUrl), svcClientCreds,
new DelegatingHandler[] { new MyAzureTracingHandler() });
//make call to OData controller...
MyCorp.ApiClient.Models.ODataResponseListStatus statusList = await client.Status.GetStatusAsync(expand: "StatusType",cancellationToken: defaultCancelThreadToken);
return View(statusList.Value);
我已经尝试了上述的变体,使用了 TokenCredentials
的不同 ctor,但无论如何,我可以将我的断点放在 MyAzureTracingHandler
中并看到请求没有授权 headers 应用.. 所以我得到了预期的 401 Unauthorized
响应。
如果我修改 MyAzureTracingHandler
以接受我的 TokenCredentials
实例,那么我可以强制请求应用适当的不记名令牌。
这有效,但是,感觉 hack-ish:
我更改了原来的客户端实例化片段:
client = new ApiClient(new Uri(apiRsrcUrl), svcClientCreds,
new DelegatingHandler[] { new MyAzureTracingHandler() });
为此:
client = new ApiClient(new Uri(apiRsrcUrl), svcClientCreds,
new DelegatingHandler[] { new MyAzureTracingHandler(svcClientCreds) });
在 MyAzureTracingHander
的 SendAsync
方法中,我这样做:
await svcClientCreds.ProcessHttpRequestAsync(request, cancellationToken);
我做错了什么吗?我认为在实例化我的客户端时我不应该两次传递 ServiceClientCredentials
。
附录 A - 通过 ADAL 获取访问令牌:
private string clientId = ConfigurationManager.AppSettings["ida:ClientId"];
private string appKey = ConfigurationManager.AppSettings["ida:ClientSecret"];
private string tslResourceID = ConfigurationManager.AppSettings["ross:TslWebApiResourceId"];
private static string loginRedirectUri = ConfigurationManager.AppSettings["ross:LoginRedirectUri"];
private AuthenticationContext authContext;
private AuthenticationResult authenticationResult;
public async Task<string> GetTokenString()
{
string signedInUserID = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
string tenantID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
string userObjectID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
try
{
// get a token for the Graph without triggering any user interaction (from the cache, via multi-resource refresh token, etc)
ClientCredential clientcred = new ClientCredential(clientId, appKey);
// initialize AuthenticationContext with the token cache of the currently signed in user, as kept in the app's database
authContext = new AuthenticationContext(Startup.Authority, new ADALTokenCache(userObjectID));
UserIdentifier userIdentifier = new UserIdentifier(userObjectID, UserIdentifierType.UniqueId);
authenticationResult = await authContext.AcquireTokenSilentAsync(tslResourceID, clientcred, userIdentifier);
}
catch(AdalException ex)
{
throw ex;
}
return authenticationResult.AccessToken;
}
虽然我相信我 运行 我的 autorest
命令带有 --add-credentials
,但我可能使用了旧语法... --AddCredentials true
我也没有像文档建议的那样运行autorest --reset
其中一个是罪魁祸首,因为现在我的 1.1.0 autorest 安装正确生成了所有内容。
编辑 10/24 我认为这很可能是用户错误 - 在深入探讨这个问题之前,请参阅下面的答案以寻求补救措施
TL;DR: 对于我的 OAuth 2.0 代码流...
Why does my
TokenCredentials
not work with my AutoRest client? I'm getting NO bearer token applied to the request / no Authorization header set
我知道我的管道已经工作了..
使用来自 this azure sample 的代码,它不是 AutoRest 客户端,我可以成功地获取我的 access_token
并且可以从我的受保护的 Web API 项目中获取 JSON。 .所以我排除了所有先决条件..我知道我的管道有效
我的 AutoRest 设置..
1.) 下载自 GitHub this AutoRest repo v1.1.0
2.) 下载我的 swagger JSON 到磁盘,保存为 swagger.json
3.) 运行 这个 command-line 生成 C# 文件:
autorest --input-file=swagger.json --csharp --output-folder=MyCorp_ApiClient_Tsl --namespace='MyCorp.ApiClient' --add-credentials
4.) 将生成的 类 复制到我的 .NET 4.6.2 网站
5.) 这些是我的 NuGet:
- Microsoft.Rest.ClientRuntime version="2.3.8"
- Microsoft.Rest.ClientRuntime.Azure.Authentication version="2.3.1"
- Microsoft.IdentityModel.Clients.ActiveDirectory version="2.28.3"
这是不起作用的地方:
AdalTokenHelper tokenHelper = new AdalTokenHelper();//helper code further below
string token = await tokenHelper.GetTokenString();
var svcClientCreds = new TokenCredentials(token, "Bearer");
client = new MyCorp.ApiClient(new Uri(apiRsrcUrl), svcClientCreds,
new DelegatingHandler[] { new MyAzureTracingHandler() });
//make call to OData controller...
MyCorp.ApiClient.Models.ODataResponseListStatus statusList = await client.Status.GetStatusAsync(expand: "StatusType",cancellationToken: defaultCancelThreadToken);
return View(statusList.Value);
我已经尝试了上述的变体,使用了 TokenCredentials
的不同 ctor,但无论如何,我可以将我的断点放在 MyAzureTracingHandler
中并看到请求没有授权 headers 应用.. 所以我得到了预期的 401 Unauthorized
响应。
如果我修改 MyAzureTracingHandler
以接受我的 TokenCredentials
实例,那么我可以强制请求应用适当的不记名令牌。
这有效,但是,感觉 hack-ish:
我更改了原来的客户端实例化片段:
client = new ApiClient(new Uri(apiRsrcUrl), svcClientCreds,
new DelegatingHandler[] { new MyAzureTracingHandler() });
为此:
client = new ApiClient(new Uri(apiRsrcUrl), svcClientCreds,
new DelegatingHandler[] { new MyAzureTracingHandler(svcClientCreds) });
在 MyAzureTracingHander
的 SendAsync
方法中,我这样做:
await svcClientCreds.ProcessHttpRequestAsync(request, cancellationToken);
我做错了什么吗?我认为在实例化我的客户端时我不应该两次传递 ServiceClientCredentials
。
附录 A - 通过 ADAL 获取访问令牌:
private string clientId = ConfigurationManager.AppSettings["ida:ClientId"];
private string appKey = ConfigurationManager.AppSettings["ida:ClientSecret"];
private string tslResourceID = ConfigurationManager.AppSettings["ross:TslWebApiResourceId"];
private static string loginRedirectUri = ConfigurationManager.AppSettings["ross:LoginRedirectUri"];
private AuthenticationContext authContext;
private AuthenticationResult authenticationResult;
public async Task<string> GetTokenString()
{
string signedInUserID = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
string tenantID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
string userObjectID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
try
{
// get a token for the Graph without triggering any user interaction (from the cache, via multi-resource refresh token, etc)
ClientCredential clientcred = new ClientCredential(clientId, appKey);
// initialize AuthenticationContext with the token cache of the currently signed in user, as kept in the app's database
authContext = new AuthenticationContext(Startup.Authority, new ADALTokenCache(userObjectID));
UserIdentifier userIdentifier = new UserIdentifier(userObjectID, UserIdentifierType.UniqueId);
authenticationResult = await authContext.AcquireTokenSilentAsync(tslResourceID, clientcred, userIdentifier);
}
catch(AdalException ex)
{
throw ex;
}
return authenticationResult.AccessToken;
}
虽然我相信我 运行 我的 autorest
命令带有 --add-credentials
,但我可能使用了旧语法... --AddCredentials true
我也没有像文档建议的那样运行autorest --reset
其中一个是罪魁祸首,因为现在我的 1.1.0 autorest 安装正确生成了所有内容。