首页 > 解决方案 > 使用 adalFetch 从 API 调用返回的“AADSTS500011”错误消息

问题描述

我有一个在 Azure Active Directory 中注册的 React 应用程序。在 API 权限部分,我添加了访问我尝试访问的 API 的权限。

当用户进入应用程序时,我正在使用 react-adal 包来处理登录和访问令牌的存储。我的理解是,此时创建了 API 的访问令牌,并且 adalFetch 在调用 API 期间处理物流。

API 的响应是一个错误对象(我替换了实际的 id;是的,它们完全匹配并且在 AAD 中是正确的):

{
message: "AADSTS500011: The resource principal named https://<domain>.onmicrosoft.com/APP_ID/access_as_user was not found in the tenant named TENANT. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You might have sent your authentication request to the wrong tenant."
msg: "invalid_resource"
}

我搜索了高低,以找到解决此问题的原因。有关于 API 的文档,但没有指定资源或超出各种端点的任何内容,即http://thing-api.azurewebsites.net/api/endpointGoesHere

API页面指出:

要使用 API,应用需要使用 AzureAD (AAD) 实现现代身份验证 (OIDC),然后从 AAD 请求 API 的令牌。

Azure 中的应用程序 ID 是https://domain.onmicrosoft.com/APP_ID并且需要“access_as_user”范围。

adalConfig.js

import { AuthenticationContext, adalFetch, withAdalLogin } from 'react-adal';

export const adalConfig = {
  clientId: CLIENT_ID,
  tenant: TENANT,
  endpoints: {
    thingApi: 'https://<domain>.onmicrosoft.com/APP_ID/access_as_user',
    graphApi: 'https://graph.microsoft.com',
  },
  cacheLocation: 'localStorage',
};

export const authContext = new AuthenticationContext(adalConfig);

export const adalApiFetch = (fetch, url, options) =>
  adalFetch(authContext, adalConfig.endpoints.thingApi, fetch, url, options);

export const adalGraphFetch = (fetch, url, options) =>
  adalFetch(authContext, adalConfig.endpoints.graphApi, fetch, url, options);

API 调用的函数。在 componentDidMount 中执行。

TrainLanding.jsx

//Returns error
fetchData = () => {
    adalApiFetch(fetch, 'http://thing-api.azurewebsites.net/api/EventGet', {})
      .then((response) => {
        response.json()
          .then((responseJson) => {
            this.setState({ apiResponse: JSON.stringify(responseJson, null, 2) }, () => {
              console.log(this.state.apiResponse)
            })
          });
      })
      .catch((error) => {
        console.error(error);
      })
  }

//works perfectly fine
fetchGraph = () => {
    adalGraphFetch(fetch, 'https://graph.microsoft.com/v1.0/me', {})
      .then((response) => {
        response.json()
          .then((responseJson) => {
            this.setState({ apiResponse: JSON.stringify(responseJson, null, 2) }, () => {
              console.log(this.state.apiResponse)
            })
          });
      })
      .catch((error) => {
        console.error(error);
      })
  }

我以完全相同的方式设置了一个图形 API 调用来测试该方法,它工作得非常好。所以我知道 adal 设置正确,我只是不明白错误和哪里出错了。我的谷歌搜索没有产生任何有用的结果。

标签: reactjsrestazure-active-directoryadal

解决方案


好的,所以如果您在这里,请注意以下几点:

  1. 不要使用 ADAL。使用 MSAL。ADAL 是 v1 并且不起作用。在此处阅读示例:https ://www.npmjs.com/package/react-aad-msal
  2. 您应该将整个应用程序包装在从上面获得的组件中。我将在下面展示我是如何做到的。
  3. 您必须已在 Azure Active Directory 中注册您的应用、配置重定向 URL 并包含 API 权限。

index.js

import { AzureAD, MsalAuthProviderFactory, LoginType } from 'react-aad-msal';
import { msalConfig, authParams } from './msalConfig';

class Index extends Component {
  state = {
    userInfo: null,
  }

  userJustLoggedIn = (accInfo) => {
    this.setState({
      userInfo: accInfo
    })
  }

  render() {
    return(
      <AzureAD
      provider={
        new MsalAuthProviderFactory(msalConfig, authParams, LoginType.Redirect)
      }
      forceLogin={true}
      accountInfoCallback={this.userJustLoggedIn}
        >
        <HashRouter>
          <App userInfo={this.state.userInfo}/>
        </HashRouter>
      </AzureAD>
    );
  }
}


  ReactDOM.render(
    <Index/>, document.getElementById('root')
  );

如果您使用的是最新版本的 Create React App,这可能不是您的索引的样子。出于几个原因,我将索引转换为组件。首先,我的身份验证循环在重定向时卡住了 1 次刷新。其次,我可以将登录用户的信息存储在状态中,使用 setState 进行更新(这会强制进行另一个渲染),然后将其作为道具传递给我的应用程序的其余部分。

msalConfig.js

export const msalConfig = {
  auth: {
    authority: process.env.REACT_APP_AUTHORITY, //this should be "https://login.microsoftonline.com/<your-tenant-id>"
    clientId: process.env.REACT_APP_CLIENT_ID, //just "<your-client-id>"
    redirectUri: process.env.REACT_APP_REDIRECT //"<url of your app or localhost port you dev on>"
  },
  cache: {
    cacheLocation: "localStorage",
    storeAuthStateInCookie: true
  }
};

export const authParams = {
//can be whatever api scopes you need here **as long as they are from the same API address**
  scopes: [
    'https://graph.microsoft.com/User.ReadBasic.All',
    'https://graph.microsoft.com/email',
    'https://graph.microsoft.com/profile',
    'https://graph.microsoft.com/User.Read'
  ],
  extraScopesToConsent: [
    //any non Microsoft Graph API scopes go here for this example
    'any extra strings of APIs to consent to'
  ]
}

在此处阅读上述环境文件和变量:https ://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#what-other-env-files-can-be-used

我有一个 .env.development 和一个 .env.production ,每个都有正确的重定向 URL。


对用户进行身份验证后,您可以访问 API。

您需要在每次 API 调用之前静默获取令牌并在请求中使用令牌。对我来说,它看起来像这样:

const authProvider = new MsalAuthProviderFactory(msalConfig, authParams);
    console.log(authProvider)
    authProvider.getAuthProvider().UserAgentApplication.acquireTokenSilent(authParams)
    .then((res) => {
      axios({
        headers: {
          'Authorization': 'Bearer ' + res.accessToken
        },
        method: 'GET',
        url: "api address"
      })
      .then((response) => {
        //do stuff with response
        console.log(response)
      })
      .catch((error) => {
        console.log('axios fail: ' + error)
      })
    })
    .catch((error) => {
      console.log('token fail: ' + error)
    })

我将它放入一个函数并在 componentDidMount 期间调用。

如果有任何变化,我会更新。我希望这可以帮助别人。


推荐阅读