无法从Azure AD获取承载令牌以用于API应用程序。

6
我有一个MVC应用程序,需要访问在Azure中受Azure AD身份验证保护的私有API应用程序。因此,我需要获取Azure AD承载令牌,将其转换为Zumo-Auth令牌,并使用它来访问API应用程序。
我正在按照此教程进行操作,一切都很顺利,直到我需要从authContext请求令牌的那一点。以下是代码片段:
var authContext = new AuthenticationContext(
    "https://login.microsoftonline.com/MyADDomain.onmicrosoft.com");

ClientCredential credential = new ClientCredential(
    "04472E33-2638-FAKE-GUID-F826AF4928DB", 
    "OMYAPIKEY1x3BLAHEMMEHEHEHEHEeYSOMETHINGRc=");

// Get the AAD token.
var appIdUri = 
    "https://MyAppGateway-814485545465FAKE4d5a4532cd.azurewebsites.net/login/aad";

//var appIdUri = "https://MyADDomain.onmicrosoft.com/MyAppName";
//var appIdUri = "https://MyADDomain.onmicrosoft.com/";
//var appIdUri = "https://graph.windows.net";

AuthenticationResult result = 
    authContext.AcquireToken(appIdUri, credential); // <-- can't get the token from AD

// downhill from here
var aadToken = new JObject();
aadToken["access_token"] = result.AccessToken;
var appServiceClient = new AppServiceClient(
    "https://MyAppGateway-814485545465FAKE4d5a4532cd.azurewebsites.net/");

// Send the AAD token to the gateway and get a Zumo token
var appServiceUser = await appServiceClient.LoginAsync("aad", aadToken);

这一行代码 authContext.AcquireToken(appIdUri, credential) 造成了问题。

如果我将 appIdUri 设置为 https://MyAppGateway-814485545465FAKE4d5a4532cd.azurewebsites.net/login/aad,就会出现异常:

400: AdalServiceException: AADSTS50001: 资源 'https://MyAppGateway-814485545465FAKE4d5a4532cd.azurewebsites.net/login/aad' 未在该帐户中注册。

但是,这一行代码确实在 AD 应用程序的 Reply Url 列表中。

Reply URI in Azure AD Application

当我尝试将 appIdUri 设置为 https://MyADDomain.onmicrosoft.com/MyAppName 或者 https://MyADDomain.onmicrosoft.com/ 时,我会收到另一条异常消息:

400: AdalServiceException: AADSTS50105: 应用程序 '04472E33-2638-FAKE-GUID-F826AF4928DB' 未分配给 'https://MyADDomain.onmicrosoft.com/MyAppName' 应用程序的角色

或者

400: AdalServiceException: AADSTS50105: 应用程序 '04472E33-2638-FAKE-GUID-F826AF4928DB' 未分配给 'https://MyADDomain.onmicrosoft.com/' 应用程序的角色

在这两种情况下,我都将 AD 应用程序的 App ID URI 设置为 'https://MyADDomain.onmicrosoft.com/MyAppName' 或者 'https://MyADDomain.onmicrosoft.com/'。这两个名称都在 Reply URL 列表中。

最终,在尝试了足够多次之后,我将 appIdUri 设置为 https://graph.windows.net 并获得了令牌。但是该令牌的过期日期已经过去(大约过去了1分钟),所以我不能进一步使用它。尝试使用该令牌登录 API 应用程序时会出现 401-未经身份验证 的错误。

我漏掉了什么?

什么是 Zumo-Auth 令牌?它与你的问题有多大关联? - Shaun Luttin
1
@ShaunLuttin Zumo-Auth 是 Azure 中用于身份验证的 ApiApp 和移动应用程序使用的令牌。我需要它来与 ApiApp 进行身份验证。我猜对于这个问题来说并不重要,因为我似乎无法获取承载令牌,这是一个先决步骤。 - trailmax
您能通过浏览器登录吗?即,您能否通过浏览器完成此步骤:https://azure.microsoft.com/zh-cn/documentation/articles/app-service-api-dotnet-add-authentication/#prerequisites - Shaun Luttin
是的,通过浏览器登录没有问题 - 要求我输入 MS 密码并让我使用 API。不过现在我不太确定了 - 在实验期间我改变了很多东西,可能已经出了问题。回到办公室后我会再次核实。谢谢这个提示 - 我没有想到要再次核实这个问题。 - trailmax
好的,如果那个能正常工作,那么我的答案现在可能也可以。 - Shaun Luttin
1个回答

9
我已经按照您提供的教程进行了操作:从受Azure Active Directory认证的Web应用客户端调用Azure API应用程序 以下是需要完成的步骤:
  1. 创建一个返回联系人数据的Azure API Api。
  2. 将API应用部署到Azure App Service。
  3. 使用Azure Active Directory保护API应用。
然后我成功获取了令牌,如下示例所示,我的代码与您的代码没有任何区别,只是它使用了更新版本的Microsoft.IdentityModel.Clients.ActiveDirectory库并使用了Async

从AAD获取访问令牌

class Program
{
    static void Main(string[] args)
    {
        var authContext = new AuthenticationContext(Constants.AUTHORITY);
        var credential = 
            new ClientCredential(Constants.CLIENT_ID, Constants.CLIENT_SECRET);
        var result = (AuthenticationResult)authContext
            .AcquireTokenAsync(Constants.API_ID_URL, credential)
            .Result;
        var token = result.AccessToken;
        Console.WriteLine(token.ToString());
        Console.ReadLine();
    }
}

常量

AUTHORITY. 这个的第一个段是 https://login.microsoftonline.com。最后一段是 允许的租户。我们在 portal.azure.com 中设置了允许的租户,进入我们应用程序的网关,选择“设置”>“标识”>“Azure Active Directory”>“允许的租户”。我的租户是 bigfontoutlook.onmicrosoft.com。

CLIENT_ID. 我们从添加到 Azure Active Directory 的应用程序中检索此客户端 ID。在 manage.windowsazure.com 中找到此项 > Active Directory > 您的目录 > 应用程序 > 您的应用程序 > 配置。检索到后,我们必须将其添加到我们的网关的 Azure Active Directory 设置中的客户端 ID 字段中。

CLIENT_SECRET. 我们在与检索客户端 ID 相同的位置创建/检索此项。

API_ID_URL. 我们通过选择“设置”>“标识”>“Azure Active Directory”>“应用 URL”在我们的 Web API 应用程序的网关中检索此项。

这些对我有效。

class Constants
{
    public const string AUTHORITY =
     "https://login.microsoftonline.com/bigfontoutlook.onmicrosoft.com/";

    public const string CLIENT_ID = 
      "0d7dce06-c3e3-441f-89a7-f828e210ff6d";

    public const string CLIENT_SECRET =
      "AtRMr+Rijrgod4b9Q34i/UILldyJ2VO6n2jswkcVNDs=";

    public const string API_ID_URL = 
      "https://mvp201514929cfaaf694.azurewebsites.net/login/aad";
}

最终解码的JWT

这里是解码后的JWT访问令牌所包含的内容。

{
 typ: "JWT",
 alg: "RS256",
 x5t: "MnC_VZcATfM5pOYiJHMba9goEKY",
 kid: "MnC_VZcATfM5pOYiJHMba9goEKY"
}.
{
 aud: "https://mvp201514929cfc350148cfa5c9b24a7daaf694.azurewebsites.net/login/aad",
 iss: "https://sts.windows.net/0252f597-5d7e-4722-bafa-0b26f37dc14f/",
 iat: 1442346927,
 nbf: 1442346927,
 exp: 1442350827,
 ver: "1.0",
 tid: "0252f597-5d7e-4722-bafa-0b26f37dc14f",
 oid: "5a6f33eb-b622-4996-8a6a-600dce355389",
 sub: "5a6f33eb-b622-4996-8a6a-600dce355389",
 idp: "https://sts.windows.net/0252f597-5d7e-4722-bafa-0b26f37dc14f/",
 appid: "0d7dce06-c3e3-441f-89a7-f828e210ff6d",
 appidacr: "1"
}.

注意:这是一个一次性使用的应用,在一次性的活动目录帐户和一次性的资源组中,因此显示我的安全凭据不是问题。

仅供确认的图示 :)

使用Azure ADD连接各个点


谢谢,明天我会试一下。 - trailmax
1
你知道吗?我复制了你的代码,放置了我的 GUID、secrets 和 URLs。但仍然得到相同可恶的异常!于是我创建了一个全新的 API 应用和一个新的 AD 应用程序。复制了凭据后一切正常工作。不确定到底哪里出了问题,但我怀疑 AD 应用程序已经无法修复了。 - trailmax
是的,有时候故障排除会弄得一团糟 :) - Shaun Luttin
我只想补充一下,我遇到了完全相同的问题,出现了完全相同的错误和解决方案(重新开始并再试一次)。问题是,我现在已经重新开始尝试了大约8次,只有5次成功了。这个工具似乎不太可靠,我不知道这是因为工具的预览性质还是其他原因,但它似乎不太可靠。 :-/ - Jaxidian
@Jaxidian 我曾经在OAuth方面遇到过类似的问题,结果发现是使用HTTP和HTTPS之间的差异。你有检查过吗? - Shaun Luttin
@ShaunLuttin 谢谢。幸运的是(不幸的是?)我已经找到了这种不可预测的行为。只要考虑到“需要用户分配?”设置的延迟启用,它就是可预测的。启用该设置(并等待一分钟),它就会100%失败,并出现OP的错误。无论如何,我似乎无法弄清楚如何“分配”客户端应用程序给Web API应用程序。 - Jaxidian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接