尝试在 Azure 函数中验证 Azure AD returns 401,"IDX10516: Signature validation failed."

Attempting to authenticate Azure AD in Azure Function returns 401, "IDX10516: Signature validation failed."

我正在尝试使用 Azure Function web API 和连接到 Azure AD 的 react-based SPA 构建 SSO 原型。目标是使用“Easy Auth”(又名 Azure Function 集成身份验证)在 Azure Function (https://docs.microsoft.com/en-us/azure/app-service/overview-authentication-authorization) 上使用 Microsoft Identity Platform 作为我的提供者进行身份验证。

首先,我使用以下教程创建了一个 React SPA:https://docs.microsoft.com/en-us/azure/active-directory/develop/tutorial-v2-react 这似乎验证得很好,我能够使用示例 Graph API 调用。

但是,一旦我尝试将 Azure 函数添加到组合中,我 运行 就遇到了问题。我使用 POST 调用“Client-directed sign-in” (https://docs.microsoft.com/en-us/azure/app-service/configure-authentication-customize-sign-in-out#client-directed-sign-in) 来提交我的访问令牌,但它失败了。

我在调用以下函数的页面中创建了一个新按钮:

export async function callExampleService(idToken, accessToken) {
    const headers = new Headers();

    headers.append("Content-Type", "application/json");

    const options = {
        method: 'POST',
        headers: headers,
        body: JSON.stringify({ access_token: `${accessToken}` })
    };

    return fetch(exampleDataServiceConfig.exampleDataServiceBase.concat(exampleDataServiceConfig.postAuth), options)
        .then(response => response.json())
        .catch(error => console.log(error));
}

从 Fiddler 响应来看,调用似乎符合预期 POST:

POST https://<function-name>/.auth/login/aad HTTP/1.1
Host: func-dotnetssoprototype-dev-westus2-001.azurewebsites.net
Connection: keep-alive
Content-Length: 1942
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="101", "Microsoft Edge";v="101"
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.41 Safari/537.36 Edg/101.0.1210.32
sec-ch-ua-platform: "Windows"
content-type: application/json
Accept: */*
Origin: http://localhost:3000
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://localhost:3000/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9

{"access_token":"<valid JWT token from client app auth, tested on jwt.io>"}

但返回以下错误:

HTTP/1.1 401 Unauthorized
Content-Type: application/json
Vary: Origin
Server: Kestrel
WWW-Authenticate: Bearer realm="<function-name>.azurewebsites.net"
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: http://localhost:3000
Request-Context: appId=cid-v1:5c2eaf04-be8a-4b4d-baca-bd047b53cfb0
Strict-Transport-Security: max-age=31536000; includeSubDomains
Date: Thu, 05 May 2022 00:03:00 GMT
Content-Length: 716

{"code":401,"message":"IDX10516: Signature validation failed. Unable to match key: \nkid: '[PII of type 'System.String' is hidden. For more details, see https:\/\/aka.ms\/IdentityModel\/PII.]'. \nNumber of keys in TokenValidationParameters: '0'. \nNumber of keys in Configuration: '6'. \nExceptions caught:\n '[PII of type 'System.Text.StringBuilder' is hidden. For more details, see https:\/\/aka.ms\/IdentityModel\/PII.]'. \ntoken: '[PII of type 'System.IdentityModel.Tokens.Jwt.JwtSecurityToken' is hidden. For more details, see https:\/\/aka.ms\/IdentityModel\/PII.]'. Valid Lifetime: 'True'. Valid Issuer: '[PII of type 'System.Boolean' is hidden. For more details, see https:\/\/aka.ms\/IdentityModel\/PII.]'"}

需要注意的是,react 客户端应用程序和 azure 函数都使用相同的注册应用程序凭据进行身份验证。我还没有找到任何关于这是正确做法还是两者都需要单独注册应用程序的详细信息。

这里有一些相关信息可以缩小问题范围:

由于身份验证是在黑盒容器中完成的,我不确定我可以采取哪些步骤来获取有关此问题的具体信息。我有以下问题:

  1. 有没有办法在函数上“un-hide”PII?我在错误中看到了 link,它引用了添加“IdentityModelEventSource.ShowPII = true;”到代码,但这个源不在 Azure 包中,我认为这是 auth 容器的错误。
  2. 什么可能导致签名失败 validation/how 我可以解决这个问题吗?我查看了 JWT 中的“孩子”和众所周知的配置。它存在于返回的清单中。

如有任何帮助,我们将不胜感激。

我缩小范围后问题很简单。

问题是我使用的是 accessToken 而不是 idToken 来进行身份验证。 json 属性 被称为“access_token”的事实用词不当。

代码更改为:

body: JSON.stringify({ access_token: `${idToken}` })