如何将 azure 广告集成到也在 azure 中使用 REST API 的 React Web 应用程序中

How to integrate azure ad into a react web app that consumes a REST API in azure too

我有一个 React 网络应用程序,我已经为该网络应用程序本身配置了 Azure AD 身份验证。它的 100% 客户端站点应用程序,没有服务器端组件。

我使用了这个组件: https://github.com/salvoravida/react-adal

我的代码如下: adalconfig.js

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

export const adalConfig = {
  tenant: 'mytenantguid',
  clientId: 'myappguid',
  endpoints: {
    api: '14d71d65-f596-4eae-be30-27f079bf8d4b',
  },
  cacheLocation: 'localStorage',
};

export const authContext = new AuthenticationContext(adalConfig);

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

export const withAdalLoginApi = withAdalLogin(authContext, adalConfig.endpoints.api);

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import DashApp from './dashApp';
import registerServiceWorker from './registerServiceWorker';
import 'antd/dist/antd.css';

import { runWithAdal } from 'react-adal';
import { authContext } from './adalConfig';

const DO_NOT_LOGIN = false;

runWithAdal(authContext, () => {

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

  // Hot Module Replacement API
  if (module.hot) {
    module.hot.accept('./dashApp.js', () => {
      const NextApp = require('./dashApp').default;
      ReactDOM.render(<NextApp />, document.getElementById('root'));
    });
  }

},DO_NOT_LOGIN);


registerServiceWorker();

dashapp.js

import React from "react";
import { Provider } from "react-redux";
import { store, history } from "./redux/store";
import PublicRoutes from "./router";
import { ThemeProvider } from "styled-components";
import { LocaleProvider } from "antd";
import { IntlProvider } from "react-intl";
import themes from "./settings/themes";
import AppLocale from "./languageProvider";
import config, {
  getCurrentLanguage
} from "./containers/LanguageSwitcher/config";
import { themeConfig } from "./settings";
import DashAppHolder from "./dashAppStyle";
import Boot from "./redux/boot";

const currentAppLocale =
  AppLocale[getCurrentLanguage(config.defaultLanguage || "english").locale];


const DashApp = () => (
  <LocaleProvider locale={currentAppLocale.antd}>
    <IntlProvider
      locale={currentAppLocale.locale}
      messages={currentAppLocale.messages}
    >
      <ThemeProvider theme={themes[themeConfig.theme]}>
        <DashAppHolder>
          <Provider store={store}>
            <PublicRoutes history={history} />
          </Provider>
        </DashAppHolder>
      </ThemeProvider>
    </IntlProvider>
  </LocaleProvider>
);
Boot()
  .then(() => DashApp())
  .catch(error => console.error(error));

export default DashApp;
export { AppLocale };

到那时一切正常,当用户未通过身份验证时,它会被重定向到 login.live.com 进行身份验证,然后再被重定向回来。

但是我还创建了另一个用于托管 REST API 的 azure webapp,REST API 已经在 Azure AD 中配置,因此尝试使用其余部分的用户将需要进行身份验证.

现在的问题是:如何设置我的客户端应用程序以使用受 Azure AD 保护的 REST API?

我找到了这个并且看起来是我要找的东西,但我不确定如何将它集成到我上面的现有代码中

https://github.com/AzureAD/azure-activedirectory-library-for-js/issues/481

更新: 对于潜在读者

这个答案加上这个 url 配置应用程序注册的说明帮助我解决了问题:https://blog.ithinksharepoint.com/2016/05/16/dev-diary-s01e06-azure-mvc-web-api-angular-and-adal-js-and-401s/

这里的关键是adalApiFetch,在adalConfig.js中定义。如您所见,它是 adalFetch 的简单包装器。此方法(在 react-adal 中定义)接收一个 ADAL 实例 (authContext)、一个资源标识符 (resourceGuiId)、一个方法 (fetch)、一个 URL (url) 和一个对象 (options)。该方法执行以下操作:

  1. 使用 ADAL 实例 (authContext) 获取由 resourceGuiId 标识的资源的访问令牌。
  2. 将此访问令牌添加到 options 对象的 headers 字段(如果未提供,则创建一个)。
  3. 调用给定的 "fetch" 方法,传入 urloptions 对象作为参数。

adalApiFetch 方法(您已在 adalConfig.js 中定义)仅使用 adalConfig.endpoints.api 中标识的资源调用 adalFetch

好的,那么您如何使用所有这些来发出 REST 请求,并在您的 React 应用程序中使用响应?让我们举个例子。在以下示例中,我们将使用 Microsoft Graph API 作为受 Azure AD 保护的 REST API。我们将通过它的友好标识符 URI(“https://graph.microsoft.com”)来识别它,但请记住,它也可以是 Guid 应用程序 ID。

adalConfig.js 定义 ADAL 配置,并导出几个辅助方法:

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

export const adalConfig = {
tenant: '{tenant-id-or-domain-name}',
clientId: '{app-id-of-native-client-app}',
endpoints: {
    api: 'https://graph.microsoft.com' // <-- The Azure AD-protected API
},
cacheLocation: 'localStorage',
};

export const authContext = new AuthenticationContext(adalConfig);

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

export const withAdalLoginApi = withAdalLogin(authContext, adalConfig.endpoints.api);

index.js 使用 react-adal 中的 runWithAdal 方法包装 indexApp.js,确保用户使用 Azure AD 签名加载前 indexApp.js:

import { runWithAdal } from 'react-adal';
import { authContext } from './adalConfig';

const DO_NOT_LOGIN = false;

runWithAdal(authContext, () => {

// eslint-disable-next-line
require('./indexApp.js');

},DO_NOT_LOGIN);

indexApp.js 只是加载并渲染 App 的一个实例,这里没什么特别的:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';

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

App.js 是一个神奇的简单组件:

  • 我们定义了一个state值。在这种情况下,它被称为 apiResponse 因为我们只是显示原始的 API 响应,但是当然你可以随意命名这个状态(或者有多个状态值)。
  • componentDidMount 期间(在 DOM 中元素可用之后 运行),我们调用 adalApiFetch。我们传入 fetch(来自 Fetch API 作为 fetch 参数,以及我们要发出的 REST 请求的端点(Microsoft Graph 中的 /me 端点,在此案例):
  • render方法中,我们简单地在<pre>元素中显示这个状态值。
import React, { Component } from 'react';
import { adalApiFetch } from './adalConfig';

class App extends Component {

  state = {
    apiResponse: ''
  };

  componentDidMount() {

    // We're using Fetch as the method to be called, and the /me endpoint 
    // from Microsoft Graph as the REST API request to make.
    adalApiFetch(fetch, 'https://graph.microsoft.com/v1.0/me', {})
      .then((response) => {

        // This is where you deal with your API response. In this case, we            
        // interpret the response as JSON, and then call `setState` with the
        // pretty-printed JSON-stringified object.
        response.json()
          .then((responseJson) => {
            this.setState({ apiResponse: JSON.stringify(responseJson, null, 2) })
          });
      })
      .catch((error) => {

        // Don't forget to handle errors!
        console.error(error);
      })
  }

  render() {
    return (
      <div>
        <p>API response:</p>
        <pre>{ this.state.apiResponse }</pre>
      </div>
    );
  }
}

export default App;

上面给出的配置仍然存在问题。我在上面添加了更多配置并且它有效。希望对你有帮助。

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

export const adalConfig = {
tenant: '{tenant-id-or-domain-name}',
clientId: '{app-id-of-native-client-app}',
endpoints: {
    api: 'https://graph.microsoft.com'
},
cacheLocation: 'localStorage',
extraQueryParameter: 'prompt=admin_consent'
};

export const authContext = new AuthenticationContext(adalConfig);

Phillipe 的回复让我走上了正确的道路,但我仍然 运行 遇到我的令牌未被接受的问题。

aadsTS700051: response_type 'token' 没有为应用程序启用。

要解决这个问题,我需要进入我的应用程序的注册 > 清单并将 oauth2AllowImplicitFlow 设置为 true:

    "oauth2AllowImplicitFlow": true,

注销您的 Azure 帐户,重新登录,您应该会收到用户的详细信息。