使用 TFS Rest API 在 curl 中有效,但在客户端 dotnet 库中无效

Using TFS Rest API works from curl but not from client dotnet library

我正在使用库 Microsoft.VisualStudio.Services.Client 中的以下代码:

var credential = new VssBasicCredential("", "<PAT>");
var url = "<url>"";
using var vssConnection = new VssConnection(new Uri(url), credential);
await vssConnection.ConnectAsync();

失败并出现以下异常,我认为这与服务器不允许基本身份验证有关:

System.ComponentModel.Win32Exception (0x80090020): GSSAPI operation failed with error - Unspecified GSS failure.  Minor code may provide more information (SPNEGO cannot find mechanisms to negotiate).
   at System.Net.NTAuthentication.GetOutgoingBlob(Byte[] incomingBlob, Boolean throwOnError, SecurityStatusPal& statusCode)
   at System.Net.NTAuthentication.GetOutgoingBlob(String incomingBlob)
   at System.Net.Http.AuthenticationHelper.SendWithNtAuthAsync(HttpRequestMessage request, Uri authUri, ICredentials credentials, Boolean isProxyAuth, HttpConnection connection, HttpConnectionPool connectionPool, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithNtConnectionAuthAsync(HttpConnection connection, HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.AuthenticationHelper.SendWithAuthAsync(HttpRequestMessage request, Uri authUri, ICredentials credentials, Boolean preAuthenticate, Boolean isProxyAuth, Boolean doRequestAuth, HttpConnectionPool pool, CancellationToken cancellationToken)
   at System.Net.Http.DecompressionHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.DiagnosticsHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at Microsoft.VisualStudio.Services.Common.VssHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at Microsoft.VisualStudio.Services.Common.VssHttpRetryMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
   at Microsoft.VisualStudio.Services.WebApi.VssHttpClientBase.SendAsync(HttpRequestMessage message, HttpCompletionOption completionOption, Object userState, CancellationToken cancellationToken)
   at Microsoft.VisualStudio.Services.WebApi.VssHttpClientBase.SendAsync[T](HttpRequestMessage message, Object userState, CancellationToken cancellationToken)
   at Microsoft.VisualStudio.Services.Location.Client.LocationHttpClient.GetConnectionDataAsync(ConnectOptions connectOptions, Int64 lastChangeId, CancellationToken cancellationToken, Object userState)
   at Microsoft.VisualStudio.Services.WebApi.Location.VssServerDataProvider.GetConnectionDataAsync(ConnectOptions connectOptions, Int32 lastChangeId, CancellationToken cancellationToken)
   at Microsoft.VisualStudio.Services.WebApi.Location.VssServerDataProvider.ConnectAsync(ConnectOptions connectOptions, CancellationToken cancellationToken)

但是,我设法从命令行成功执行了 REST 命令

curl <url>/_apis/projects -u :<PAT>

我正在使用无法修改任何配置的 Azure Devops Server 2019。我是 运行 来自 dotnet-core Alpine docker 图片的代码。

是dotnet库的限制还是我用错了?

如果你想使用 GitHttpClient,正如@Shayki Abramczyk 指出的那样,你应该使用 vssConnection.GetClient<GitHttpClient>() 来获取 GitHttpClient 连接。

var credential = new VssBasicCredential("", "<PAT>");
var url = "<url>"";
using var vssConnection = new VssConnection(new Uri(url), credential);
GitHttpClient gitClient = vssConnection.GetClient<GitHttpClient>();

您可以按照 Microsoft 文档QuickStarts and Samples中的示例进行操作

问题出在 dotnet Docker 图像的 Alpine 发行版上,它尚不支持 gss-ntlmssp。切换到标准图像(基于Ubuntu - mcr.microsoft.com/dotnet/core/aspnet:3.1)解决了这个问题。

我收到过期的错误 AccessToken

curl 验证了这一点。

创建新令牌后,它起作用了。

我在 Docker 容器中 运行 的程序中遇到了同样的错误。原因是 PAT 已过期。这从错误消息(“SPNEGO 无法找到协商机制”)中不是很清楚。此外,过期的 PAT 在我的开发机器上仍然有效。这就是为什么我什至不认为 PAT 会过期的原因。

新生成的 PAT:一切都是 运行。