【问题标题】:React MSAL access token has invlaid signatureReact MSAL 访问令牌的签名无效
【发布时间】:2022-09-27 19:11:37
【问题描述】:

设置

msal(在另一个文件中。使用 MsalProvider 传递):

const msalInstance = new PublicClientApplication({
    auth: {
        clientId: <B2C-Application-ID>,
        authority: \"https://login.microsoftonline.com/<tenant-directory-id>\",
        redirectUri: \"http://localhost:3000\",
    },
    cache: {
        cacheLocation: \"sessionStorage\",
        storeAuthStateInCookie: false,
    }
});

进口:

import * as msal from \"@azure/msal-browser\";
import {EventType, InteractionStatus} from \"@azure/msal-browser\";

import React, {createContext, FC, useState} from \"react\";
import {useIsAuthenticated, useMsal} from \"@azure/msal-react\";
import {AuthenticationContextType} from \"../@types/authentication\";
import {EndSessionRequest} from \"@azure/msal-browser/dist/request/EndSessionRequest\";
import jwtDecode, {JwtPayload} from \"jwt-decode\";

变量:

const {instance, accounts, inProgress} = useMsal();
const isAuthenticated = useIsAuthenticated();
const [token, setToken] = useState<string | null>(null);

登录:

function loginRedirect() {
    instance.loginRedirect({
        scopes: [\"User.Read\"],
        prompt: \"select_account\"
    });
}

获取令牌:

function getToken(): string | null {
    if (token) {
        const decodedJwt = jwtDecode<JwtPayload>(token);
        if (decodedJwt.exp && decodedJwt.exp * 1000 > Date.now()) {
            return token; // Token is still valid
        }
    }

    // If token is not available or not valid anymore, acquire a new one
    if (instance.getActiveAccount() && inProgress === InteractionStatus.None) {
        const accessTokenRequest = {
            scopes: [\"User.Read\"],
            account: accounts[0]
        }

        instance.acquireTokenSilent(accessTokenRequest)
            .then(response => {
                console.log(`access token: ${response.accessToken}`);
                console.log(`id token: ${response.idToken}`);
                setToken(response.accessToken);
                return response.accessToken;
            })
            .catch(err => {
                if (err instanceof msal.InteractionRequiredAuthError) {
                    return instance.acquireTokenPopup(loginRequest)
                        .then(response => {
                            setToken(response.accessToken);
                            return response.accessToken;
                        })
                        .catch(err => {
                            console.log(err);
                        })
                } else {
                    console.log(err);
                }
            })
    } else {
        console.error(\"No account logged in to acquire token\");
    }
    return null;
}

问题

我从 msal 获取了两个令牌(ID 和访问权限)(请参阅控制台日志)。 ID 令牌已成功验证(在我的 API 和 jwt.io 上),但我的访问令牌没有(在我的 API 和 jwt.io 上都没有)。参考this microsoft documentation 我应该使用访问令牌来验证 API。

据我所知,jwt.io 确实从https://sts.windows.net/&lt;tenant-directory-id&gt;/discovery/v2.0/keys 正确获取了公钥。这意味着this solution 要么已经过时,要么不能解决我的问题。为了确保我还尝试复制和粘贴公钥,这也不起作用。

我还发现 this solution 对我也不起作用。更改scopes 会导致无休止的登录循环。

版本:

\"@azure/msal-browser\": \"^2.28.3\",
\"@azure/msal-react\": \"^1.4.7\",
\"jwt-decode\": \"^3.1.2\",

    标签: oauth-2.0 jwt azure-ad-b2c msal react-typescript


    【解决方案1】:

    一、范围

    要请求 B2C 访问令牌,您必须指定有效范围。这些也在 Azure 中设置(Azure AD B2C -> 应用注册 -> your application -> 管理 -> API 权限)。在那里你必须指定一个范围。在获取令牌时,您必须像这样指定这些范围:

    const accessTokenRequest = {
      scopes: ["https://<tenant-name>.onmicrosoft.com/<app-id>/Subscriptions.Read"],
    }
    
    await instance.acquireTokenSilent(accessTokenRequest)
      .then(response => {
        setIdToken(response.idToken);
        setAccessToken(response.accessToken);
      })
      .catch(async err => {
        if (err instanceof msal.InteractionRequiredAuthError) {
          await instance.acquireTokenPopup(accessTokenRequest)
            .then(response => {
              setIdToken(response.idToken);
              setAccessToken(response.accessToken);
            })
            .catch(err => {
              console.log(err);
            })
        } else {
          console.log(err);
        }
      })
    

    tenant-name 您可以在应用程序 ID URI 中找到它 app-id 是您的应用程序(客户端)ID your-scope 可能类似于 Subscriptions.Read

    范围的完整示例可能是:
    https://mydemo.onmicrosoft.com/12345678-0000-0000-0000-000000000000/Subscriptions.Read

    2. 令牌版本无效

    this 文章之后,sts url 用于 v1 端点。 documentation 声称:

    使用的端点 v1.0 或 v2.0 由客户端选择,仅影响 id_tokens 的版本。 accesstokenAcceptedVersion 的可能值为 1、2 或 null。如果值为null,则该参数默认为1,对应v1.0端点。

    这意味着使用的端点(在我的例子中是 v2.0)只影响了 id-token,这使得它成功验证。访问令牌仍然是 v1,因此没有经过验证的签名。

    解决方案

    要更改版本,需要在 Manifest 中将 accessTokenAcceptedVersion 设置为 2(可在 portal.azure.com -> Azure AD B2C -> App registrations -> your application -> Manage -> Manifest 上找到:

    {
      ...
      "accessTokenAcceptedVersion": 2,
      ...
    }
    

    保存更改并等待。对我来说,等待更改应用需要几个小时。我也必须申请解决方案1. Scope。之后,新令牌的iss 应该是https://login.microsoftonline.com/&lt;tenant-directory-id&gt;/v2.0 而不是sts-uri

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-10-25
      • 2021-11-28
      • 2021-03-16
      • 1970-01-01
      • 2018-09-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多