使用Hello.js无需登录会话即可反应Microsoft Outlook日历数据

时间:2019-01-11 10:42:59

标签: reactjs microsoft-graph outlook-restapi hello.js outlook-calendar

我正在创建一个React日历,它使用客户端JavaScript SDK“ hello.js”和Microsoft Graph从“ Microsoft Outlook日历”中获取数据(对于设置,我也遵循了本指南:https://docs.microsoft.com/en-us/graph/auth-register-app-v2

使用hello.login我的应用程序可以显示日历,没有任何问题...但是很遗憾,我必须在没有登录会话的情况下显示日历。

这是我的代码:

class CalendarView extends Component {
  constructor(props) {
    super(props);

    hello.init({
      microsoft: {
        id: APP_ID,
        oauth: {
          version: 2,
          auth: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
        },
        scope_delim: ' ',
        form: false,
        scope: SCOPES,
      },
    });

    const { startDate, endDate } = this.props;

    this.state = {
      // events: [],
      startDataTime: startDate.toISOString(),
      endDataTime: endDate.toISOString(),
      token: hello('microsoft').getAuthResponse().access_token,
    };
  }

在另一个组件中,我管理Microsoft Graph查询:

class EventsList extends Component {
  constructor() {
    super();
    this.state = {
      events: [],
    };
  }

  componentWillReceiveProps(nextProps) {
    const { startDate, endDate, token } = nextProps;

    // to know what is the Bearer toke
    // -> https://stackoverflow.com/questions/25838183/what-is-the-oauth-2-0-bearer-token-exactly
    axios.get(
      `https://graph.microsoft.com/v1.0/me/calendarview?startdatetime=${startDate}&enddatetime=${endDate}&orderby=start/dateTime`,
      { headers: { Authorization: `Bearer ${token}` } },
    ).then(response => this.setState({ events: response.data.value }))
      .catch((error) => {
        console.log(error.response);
      });
  }

  render() {
    const { events } = this.state;
    if (events !== null) return events.map(event => <EventList key={event.id} event={event} />);
    return null;
  }
}

奇怪的是,如果我创建console.log(token),应用程序会向我显示令牌,但是同时,我会收到“ GET ... 401(未经授权)”错误

console log token and error message

那是我的应用程序专有权

app propriety part 1

app propriety part 2

也许是Hello.js调用的问题? 我正在用Jest测试我的应用程序,但出现此错误,它可以链接到我的问题吗?

 console.error node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/virtual-console.js:29
    Error: Uncaught [TypeError: hello is not a function]

我该如何解决?

1 个答案:

答案 0 :(得分:1)

我找到了解决方案!

我不得不打2次axios呼叫:

  • 一个获得令牌的人(带有POST)
  • 在我的Microsoft图形查询(带有GET)中使用令牌的一个人

我必须在https://portal.azure.com/#home处注册我的应用,以便获得客户ID和机密。

我需要使用以下主体参数将POST消息发送到Azure Active Directory身份验证终结点后:

  • grant_type :我们要使用的流程,在我的情况下为client_credentials。
  • client_id :应用程序I的客户端ID(应用程序ID)
    在注册步骤中创建;
  • client_secret :我在注册中创建的客户机密 步骤;
  • 资源:我想访问的资源名称, https://graph.microsoft.com在这种情况下。

因此,我使用以下axios POST请求创建了一个组件:

componentDidMount() {
    axios.post(`https://cors-anywhere.herokuapp.com/https://login.microsoftonline.com/${AZURE_ACTIVE_DIRECTORY_TENANT_NAME}/oauth2/token`,
      `grant_type=${GRANT_TYPE}&client_id=${APP_ID}&client_secret=${SECRET}&resource=${RESOURCE}`).then(res => this.setAccessToken(res.data.access_token))
      .catch((error) => {
        console.error(error.response);
      });
  }

  setAccessToken(token) {
    if (typeof token === 'string') this.setState({ accessToken: token });
  }

注意 resource 值需要稍作更改才能起作用:   https%3A%2F%2Fgraph.microsoft.com%2F

我必须将字符串'https://cors-anywhere.herokuapp.com'放在micorsoftonline URL之前,因为否则应用程序会生成

“被CORS策略阻止:请求的资源上没有'Access-Control-Allow-Origin'标头。” (我不知道为什么,我仍在研究它,因为将这个字符串放在前面并不是最佳解决方案。)

在EventList组件中,我不再需要hellojs,所以我只使用生成的令牌来访问。我只需要更改一下Microsoft图形查询:

 componentDidMount() {
    const { accessToken } = this.props;
    const { startDate, endDate } = this.state;
    this.getEvents(startDate, endDate, accessToken);
  }

getEvents(startDate, endDate, accessToken) {
    const startDateString = startDate.toISOString();
    const endDateString = endDate.toISOString();
    axios.get(
      `https://graph.microsoft.com/v1.0/users/${USER_PUBLIC_ID}/calendarview?startdatetime=${startDateString}&enddatetime=${endDateString}&orderby=start/dateTime`,
      {
        headers: {
          Authorization: `Bearer ${accessToken}`,
        },
      },
    ).then(response => this.setEvents(response.data.value))
      .catch((error) => {
        console.error(error.response);
      });
  }

  setEvents(events) {
    const validEvent = event => typeof event.subject === 'string';
    this.setState({ events: events.filter(validEvent) });
  }

我希望我的解决方案也可以对其他用户有用