首页 > 解决方案 > 使用 Azure DevOps REST Api 的用户名和密码从 Azure AD 获取访问令牌

问题描述

我们正在实施 AD 注册应用程序(部署为 Azure App Service)来访问 Azure DevOps Rest Api,我遵循了为 Azure DevOps 提供的身份验证指南,并使用身份验证上下文通过发送用户名和密码获取访问令牌。尽管 MS 不推荐这种身份验证过程,但我们这样做的原因是用户帐户有权对不同组织的多个项目进行特定访问。通过这种方式,我们获取该用户的令牌并访问用户可访问的 Azure DevOps REST Api。基本上,我们创建了一个通用用户帐户,可以从我的应用程序访问 DevOps REST Api。

在本地环境中,我可以使用以下代码获取用户的访问令牌,

AuthenticationContext ctx = new AuthenticationContext("https://login.microsoftonline.com/org.onmicrosoft.com/");            
AuthenticationResult result = null;

var username = "********"; // This is your AAD username in the form user@domain.com.
var password = "********"; // This is your AAD password.            

var adalCredential = new UserPasswordCredential(username, password);
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;

try
{
    result = ctx.AcquireTokenAsync(azureDevOpsResourceId, clientId, adalCredential).Result;                
    Console.WriteLine("Token expires on: " + result.ExpiresOn);
}
catch (Exception ex)
{
    Console.WriteLine("{0}: {1}", ex.GetType(), ex.Message);
}

通过 Web 应用程序访问时相同的代码未按预期工作,并引发 ADAL 异常,

System.AggregateException: One or more errors occurred. ---> Microsoft.IdentityModel.Clients.ActiveDirectory.AdalException: parsing_wstrust_response_failed: Parsing WS-Trust response failed
   at Microsoft.IdentityModel.Clients.ActiveDirectory.Internal.WsTrust.WsTrustResponse.CreateFromResponseDocument(XDocument responseDocument, WsTrustVersion version)
   at Microsoft.IdentityModel.Clients.ActiveDirectory.Internal.WsTrust.WsTrustRequest.<SendRequestAsync>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
   at Microsoft.IdentityModel.Clients.ActiveDirectory.Internal.Flows.AcquireTokenNonInteractiveHandler.<PreTokenRequestAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
   at Microsoft.IdentityModel.Clients.ActiveDirectory.Internal.Flows.AcquireTokenHandlerBase.<RunAsync>d__57.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext.<AcquireTokenCommonAsync>d__37.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContextIntegratedAuthExtensions.<AcquireTokenAsync>d__0.MoveNext()
   --- End of inner exception stack trace ---
   at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
   at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
   at System.Threading.Tasks.Task`1.get_Result()

为什么parsing_wstrust_response_failed从应用程序运行时会发生此错误?我也想知道我们遵循的方法是否正确?我们是否有可以实施以实现我们正在寻找的替代解决方案?

标签: azure-devopsazure-active-directoryazure-devops-rest-api

解决方案


老实说,这段代码看起来不错。但是,从错误信息来看,似乎没有收到成功的响应。

我使用您的代码创建了一个测试网络应用程序以获取令牌。我的环境:.NET 框架 4.7.2 和 ADAL 5.2.7。结果是我可以成功拿到一个token。

在此处输入图像描述

因此,您可以尝试更新以使用最新的 ADAL 版本并将您的 Web 应用程序部署到新的 Web 应用程序。

如果问题依旧,可以尝试直接发起http请求获取token:

POST https://login.microsoftonline.com/{tenant-id}/oauth2/token
Content-Type: application/x-www-form-urlencoded

grant_type=password
&resource={resource}
&username={username}
&password={password}
&client_id={client-id}

在此处输入图像描述


推荐阅读