【问题标题】:Azure Function with AD auth results in 401 Unauthorized when using Bearer tokens使用不记名令牌时,带有 AD 身份验证的 Azure 函数导致 401 Unauthorized
【发布时间】:2019-08-09 02:28:57
【问题描述】:

我在 C# 中有一个非常简单的 Azure 函数,为此我设置了 Azure AD Auth。我刚刚使用 Express 设置在 Function 配置中创建了一个 App 注册。

public static class IsAuthenticated
{
    [FunctionName("IsAuthenticated")]
    public static async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get", "options", Route = null)]
        HttpRequest req,
        ILogger log)
    {
        return new OkObjectResult("You are " + req.HttpContext.User.Identity.Name);
    }
}

当我在浏览器中访问该功能时,一切都按预期工作(如果未登录,我必须登录并重定向到我的 API)。但是,如果我尝试在需要不记名令牌的任何地方访问我的函数,我会收到 401 Unauthorized 错误。更奇怪的是,我也无法在 Azure 门户中执行该功能。

但是令牌被毫无问题地获取并添加到请求中:

我尝试了几种不同的方法来解决这个问题。首先,我认为这可能是 CORS 问题(因为我也遇到过其中一些问题),只是将 CORS 设置为接受 *,但没有任何改变。

然后我将我的 API 登录端点添加到重定向并尝试将隐式授权设置为也接受访问令牌,但它仍然无法正常工作。

有什么我忽略的吗?应用注册快速配置不应该只适用于 azure 函数吗?

编辑:

按照@thomas-schreiter 的建议将指向我的函数应用程序的 URL 放入重定向中并没有改变任何东西(我已经尝试了屏幕截图中的配置,并且只是将这些值中的每一个都放在了它自己的位置上)。

编辑 2:

我现在也尝试以手动方式 with Postman 获取 Bearer 令牌,但在调用我的 API 时仍然遇到 401。

【问题讨论】:

  • 你使用哪个客户端来获取和调用azure函数?
  • 我真正的客户端应用程序是一个带有 @azure/msal-angular 的 Angular 应用程序,但我得到的错误与我只是在 Azure 门户中执行该函数一样(我在截图)。我实际上得到了一个 Bearer 令牌并将其添加到请求中,但随后我得到了 401 Unauthorized 错误
  • 我遇到了这个问题,因为我在查询字符串中提供的代码有问题,遇到这个问题的人可以先检查一下。

标签: c# azure azure-active-directory azure-functions


【解决方案1】:

如果您像我自己和原始海报一样将头撞到墙上,则可能是您允许用户从“任何组织目录(任何 Azure AD 目录 - 多租户)中的帐户和个人 Microsoft 帐户(例如 Skype、Xbox)。”

请注意,截至 2021 年 5 月,v2.0 可以完美运行。如果您使用https://login.microsoftonline.com/TENANT_ID/oauth2/v2.0/token 通过 Postman 获取令牌(如上所述),您将获得一个有效令牌,可用于验证您的 AZ 函数。

话虽如此,如果用户通过个人帐户或不在您的 AAD 中的帐户登录,则 MSAL 发出的令牌调用请求使用默认的 Microsoft 租户 ID,而不是您的租户身份证。

这就是我无法验证我的功能的原因。如果您使用租户的 AAD 中的用户登录,MSAL 非常棒且易于使用,并且一切都将按照文档中的说明进行。

【讨论】:

    【解决方案2】:

    2020-05-12 更新:根据ambrose-leung 的回答further below,您现在可以添加一个自定义颁发者 URL,它可能使您能够使用 v2 令牌。我自己没有尝试过,但也许这对将来的某人有用。 (如果他的回答对你有帮助,请给他点赞,也许可以发表评论?)


    这需要很长时间才能弄清楚,官方文档中对此的信息很少。

    但问题出在/是 Azure Functions 不支持由 oauth2/v2.0/ Azure API 生成的 Bearer 令牌。由于门户使用这些(如果您的 AD 支持它们),因此您无法在其中运行该功能。

    这也解释了为什么我的邮递员请求不起作用,因为我也在使用 v2 api。切换到 v1 后,我可以访问我的 API(Postman 不允许您在使用集成身份验证功能时添加 resource_id,因此我必须切换到手动处理所有内容)。

    之后意识到,如果您正在编写一个 JS 客户端(在我的例子中是 Angular),那么您也不能使用 MSAL。因此,另一种选择是 ADAL,其中 Angular 实现看起来有点尴尬。所以我决定使用 angular-oauth2-oidc,这又花了一个小时的时间修修补补,让它与 Azure AD 很好地配合。

    但毕竟我终于可以访问我的 API。

    我真的不明白为什么您不允许用户使用 Azure AD v2 令牌访问 Azure Function Apps,但至少这应该有更好的文档记录。不过不管怎样,我终于可以睡觉了。

    编辑:在我为此打开一个问题后,他们添加了一条说明 Azure Functions 不支持 v2,希望能让其他人的生活更轻松。

    https://docs.microsoft.com/en-us/azure/app-service/configure-authentication-provider-aad

    【讨论】:

    • 是的,谢谢谁曾否决我的答案,这实际上解决了我的问题,你真是个大人物?
    • 在哪里可以切换到 v1 端点...?我正在尝试使用 AAD B2C 并获得相同的行为。谢谢
    • 实际上忽略了这一点,我检查了我的令牌,它在 ver 声明中说 1.0,所以我想我的问题是不同的。这很痛苦....
    • FWIW,终于通过检查 JWT 中的所有声明并查看不匹配的内容来使其正常工作,结果证明发行人对我的登录流程的声明与对身份验证设置的区别函数应用。
    【解决方案3】:

    在 Function App 上设置 Active Directory 身份验证时,将管理模式设置为高级,并根据需要填写客户端 ID 和颁发者 URL(以及必要时的客户端密码)。

    重要的是,在 Allowed Token Audiences 下,输入 Application ID URI。这可以在 Expose an API 选项下的注册应用注册(在您的 AD 中)中找到。

    这是我在 Function App 上进行身份验证时所缺少的。在添加令牌受众之前,我总是会得到一个带有有效访问令牌的 401。

    这个Azure active directory - Allow token audiences 帮助我得到了答案,但我花了一段时间才意识到它指的是什么。请记住,它是可以在您的应用注册中找到的应用程序 ID URI。

    希望对你有帮助!

    【讨论】:

    • 谢谢!我今天花了几个小时在这上面。我的应用程序 ID URI 也不正确。在我的函数应用中,允许的令牌受众设置为函数应用的 url。应用程序 ID URL 完全是另外一回事! :)
    • 谢谢!对我来说,这就是解决方案。我也未能设置 Allowed Token Audience,在添加令牌受众后,使用不记名令牌的经过身份验证的请求有效。
    【解决方案4】:

    您现在可以使用 v2.0 令牌!

    在配置 AAD 时不要选择“Express”,而必须选择“Advance”并在 URL 末尾添加 /v2.0 部分。

    这是我在控制台应用程序中使用的代码,用于向用户显示登录提示,然后获取不记名令牌以用于 Azure 函数。

    string[] scopes = new string[] { "profile", "email", "openid" };
    string ClientId = [clientId of Azure Function];
    string Tenant = [tenantId];
    string Instance = "https://login.microsoftonline.com/";
    var _clientApp = PublicClientApplicationBuilder.Create(ClientId)
        .WithAuthority($"{Instance}{Tenant}")
        .WithDefaultRedirectUri()
        .Build();
    var accounts = _clientApp.GetAccountsAsync().Result;
    
    var authResult = _clientApp.AcquireTokenInteractive(scopes)
                .WithAccount(accounts.FirstOrDefault())
                .WithPrompt(Prompt.SelectAccount)
                .ExecuteAsync().Result;
    var bearerTokenForAzureFunction = authResult.IdToken;
    

    【讨论】:

    • 感谢您提供此信息,我自己还没有尝试过,所以我无法确认这是否能解决我原来的问题。但它看起来很有希望,我已经在我原来的答案中添加了一个链接到你的答案,你的名字是你的名字,所以人们将来会知道这种可能性;)
    • 谢谢,非常感谢。我的测试是当我使用 req.HttpContext.User.Identity.Name 时,我看到了我的 Azure Function 返回的电子邮件地址
    • 效果很好!
    【解决方案5】:

    我设法通过邮递员使用以下配置使其工作。 重要的一课是设置“允许的令牌受众”和邮递员用于获取令牌的“资源”名称在这种情况下应该相同。我使用了此处提供的相同代码。在这种情况下,在 Azure AD 中注册的应用程序也是客户端和资源。通过postman进行配置和测试如下

    在邮递员中获取令牌

    使用 Postman 调用 azure 函数 .. 带有承载令牌的授权标头

    【讨论】:

    • 我已经找到了我的问题的答案,但仍然感谢您的回复。您的回答实际上会帮助我找到答案,因为我之前会注意到 v1 和 v2 之间的区别。但遗憾的是,晚了一天?
    • 为什么说 oauth2 不适用于 Azure 函数。我不是使用 OAuth2 获取令牌吗
    • 问题不在于 oauth2,而是 Microsoft 有两个版本的 oauth2 API(/oauth2 与 /oauth2/v2.0)略有不同,据我所知分别使用 Azure AD v1 和 v2。
    • 是否可以在请求标头中传递 client_secret 和 Client_id?
    【解决方案6】:

    我今天面临完全相同的问题。问题原来是我在请求访问令牌时传递的资源 ID。

    例如,最初我请求这样的令牌,使用函数 URL 作为资源 id:

    AuthenticationResult authenticationResult = authenticationContext.AcquireTokenAsync("https://myfunction.azurewebsites.net", "myClientAppIdGUID", new Uri("https://login.live.com/oauth20_desktop.srf"), new PlatformParameters(PromptBehavior.SelectAccount)).Result;
    

    虽然这返回了一个访问令牌,但我在使用访问令牌调用我的函数 api 时收到了 401 未授权。

    我更改了代码以将我的函数应用 App Id 作为资源传递:

    AuthenticationResult authenticationResult = authenticationContext.AcquireTokenAsync("myFunctionAppIdGUID", "myClientAppIdGUID", new Uri("https://login.live.com/oauth20_desktop.srf"), new PlatformParameters(PromptBehavior.SelectAccount)).Result;
    

    现在一切正常。

    【讨论】:

      【解决方案7】:

      我现在唯一能想到的就是允许的观众。

      转到您的 Active Directory 设置并单击高级。在允许的令牌受众下 添加您的确切功能网址。它可能已经存在回调 url,但只需将其替换为仅函数基本 url 而无需任何回调,如图所示。

      请确保当您按下 ok 时,您还保存了您的身份验证/授权设置以生效,并在 1 分钟左右后重试。我使用 PostMan 并传递不记名令牌进行了测试,它可以工作!

      【讨论】:

      • 遗憾的是这也不起作用。是否需要任何特殊的 API 权限(应用注册)?默认情况下,只有User.Read 处于活动状态。
      • 您是否使用来自 azure AD 应用注册的客户端 ID 和密钥?或者您能否请教您是如何生成不记名令牌的?
      • 我正在使用 MSAL,您不应该使用客户端密码,只能使用客户端 ID
      【解决方案8】:

      在 AAD 应用程序本身中,转到设置 -> 回复 URL 并验证函数应用程序的 url 在列表中,其格式如下:https://mycoolapp.azurewebsites.net。如果不是,则添加它。

      如果您使用插槽,则必须为两个插槽添加它。

      【讨论】:

      • 快速安装程序已经在那里配置了身份验证路径。我尝试只将我的函数 url 和我的问题编辑中的配置放在那里,但遗憾的是它仍然无法正常工作:/ 你能想到其他可能出错的地方吗?
      • 其实没有。 :/ 我的另一个想法是 AuthorizationLevel,但它已经设置为 Anonymous。
      猜你喜欢
      • 1970-01-01
      • 2020-08-12
      • 2021-01-28
      • 1970-01-01
      • 1970-01-01
      • 2020-01-12
      • 1970-01-01
      • 2020-04-23
      • 1970-01-01
      相关资源
      最近更新 更多