Метод Microsoft Graph getSchedule приводит к ошибке InvalidAuthenticationToken с кодом 80049217 - PullRequest
0 голосов
/ 20 февраля 2020

Проблема:

Я создаю Angular веб-приложение, в котором компании могут зарегистрировать 1 своего пользователя. С помощью этой учетной записи они могут добавлять свои учетные записи ресурсов Microsoft на более позднее время, но кроме этого они ничего не могут сделать, пока не авторизуют Microsoft Graph с помощью своей учетной записи Microsoft. Когда они авторизованы (и их токен доступа сохранен), они могут получить информацию о бронировании для выбранных ими учетных записей ресурсов. Эта информация будет отображаться на разных экранах по всей компании, чтобы они знали, какие конференц-залы уже заняты или забронированы в определенный момент.

До сих пор мне удавалось завершить процесс авторизации, но при попытке получить заказы, которые я получил:

  "error": {
    "code": "InvalidAuthenticationToken",
    "message": "CompactToken parsing failed with error code: 80049217",
    "innerError": {
      "request-id": "1c24ceea-fa85-4cd0-bb0d-ab14ae26b65b",
      "date": "2020-02-19T15:54:07"
    }
  }
}

Я понятия не имею, в чем именно проблема. Я надеюсь, что есть кто-то, кто сможет мне помочь. Я хочу извиниться, потому что это мой первый пост в StackOverflow, и я не знаю, хороший ли это пост или нет, и достаточно ли информации.

Что я пробовал:

Прежде чем я начал создавать веб-приложение и API, я экспериментировал с графическим обозревателем, и там я мог выполнять запросы календаря, и ответ выглядел многообещающим, поэтому я начал работать над проектом.

Сначала я использовал процесс авторизации Процесс авторизации Microsoft от имени вошедшего в систему пользователя . Причина в том, что пользователь авторизует и запрашивает информацию о бронировании. Когда я собирался начать получать информацию о бронировании, я понял, что мы должны получить эту информацию из разных почтовых ящиков ресурса. Поэтому, поскольку обычный пользователь не может получить доступ к другим пользователям своей организации, нам нужен пользователь-администратор.

Именно тогда я узнал о процессе авторизации, который мы используем прямо сейчас, а именно авторизация Microsoft процесс без авторизации пользователя . Для этого потребуется административное согласие, и он сможет получать информацию о бронировании из нескольких почтовых ящиков ресурса.

Теперь, когда процесс авторизации завершился полностью, я хотел попробовать получить информацию о бронировании, но каждый раз, когда я получал InvalidAuthenticationToken (см. Выше для полная ошибка).

Я проверил разрешения на портале azure и изменил их в надежде, что это решит проблему, но, очевидно, нет. Итак, теперь эти разрешения выглядят так: Разрешения на портале azure (изображение)

Итак, я начал смотреть на процесс авторизации, который я сделал. Первые пользователи авторизуются через ссылку в веб-приложении Angular:

<a 
    href="https://login.microsoftonline.com/common/adminconsent
        ?client_id=**CLIENT_ID**
        &state={{user.email}}
        &redirect_uri=**REDIRECT_URL_TO_API**"
    type="button"
    class="btn btn-icon btn-danger"
    aria-label="error"
>
    <clr-icon shape="error-standard"></clr-icon>
    Authorize
</a>

Я проверил правильный идентификатор клиента, то же самое с URL-адресом, поскольку он без проблем переходит на API. Состояние - это электронная почта пользователя, потому что это необходимо позже в api loopback.

Поэтому я вхожу в систему под своей учетной записью microsoft, которая имеет права администратора, и я принял разрешения, которые просят использовать. Когда он закончил, он был перенаправлен в API, который я построил.

Этот API был полностью собран с использованием Loopback 3 , и он использует MongoDB в качестве базы данных. Таким образом, чтобы использовать loopback, мне нужно было сделать 2 модели, 1 для авторизованного пользователя (AuthUser) на сайте и 1 для токенов доступа из Microsoft Graph (MSGraphAuth). Где модель AuthUser имеет «отношение hasOne» с моделью MSGraphAuth.

Помимо используемых моделей, я установил промежуточное ПО в каталоге / server / boot. Там я отредактировал файл root. js, чтобы добавить несколько маршрутов express. Файл root. js выглядит следующим образом:

'use strict';
const express = require('express');
const erouter = require('express').Router();
var cors = require('cors');
const msauth = require('./msAuth.service');
const getbookings = require('./retrieveBookings.service');
module.exports = function(server) {
    // Install a `/` route that returns server status
    var router = server.loopback.Router();
    router.get('/', server.loopback.status());

    var app = express();
    app.use(cors({
        origin: "*"
    }));
    erouter.get('/API/auth', msauth());
    erouter.get('/API/bookings/:userid', getbookings());
    app.use(erouter);
    server.use(app);
    server.use(router);
};

Так что, когда Microsoft перенаправляет, он будет go на маршрут /API/auth, код позади выглядит так:

'use strict';
const request = require('request');
var querystring = require('querystring');
const server = require("../server");
module.exports = function() {
    return function(req, res, next) {
        var AuthUser = server.models.AuthUser;
        var user = {};
        AuthUser.find({ where: { email: req.query.state } }, function(err, au) {
            if (err) return next(err);
            if (au.length != 1) return res.redirect("https://*WEBSITE*/settings?error=user_not_found");
            user = au[0];
            if (!req.query.admin_consent) return res.redirect("https://*WEBSITE*/settings?error=permission_denied");
            const dataTokenReq = querystring.stringify({
                "client_id": process.env.client_id,
                "scope": "https://graph.microsoft.com/.default",
                "client_secret": process.env.client_secret,
                "grant_type": "client_credentials"
            });
            const postOptions = {
                url: `https://login.microsoftonline.com/${req.query.tenant}/oauth2/v2.0/token`,
                method: 'POST',
                body: dataTokenReq,
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded',
                    'Host': 'login.microsoftonline.com'
                }
            }
            request(postOptions, function(err, resp, body) {
                if (err) return next(err);
                var body = JSON.parse(body);
                const dataMsAuth = querystring.stringify({
                    "created": new Date().toDateString(),
                    "userId": user.id,
                    "token_type": body.token_type,
                    "expires": body.expires_in,
                    "access_token": body.access_token,
                    "tenant": req.query.tenant
                });
                const postMSAuth = {
                    url: "https://*API_SITE*/api/AuthUsers/" + user.id + "/msauth",
                    method: 'POST',
                    body: dataMsAuth,
                    headers: {
                        'Content-Type': 'application/x-www-form-urlencoded'
                    }
                }
                request(postMSAuth, function(err, resp, body) {
                    if (err) return next(err);
                    // Update user
                    console.log(body);
                    res.redirect("https://*WEBSITE*/settings?auth=success");
                });
            });
        });
    }
}

Итак, здесь я сначала нахожу пользователя на основе адреса электронной почты из штата, чтобы я мог добавить токены этому пользователю, но сначала я проверяю проблемы из find и admin_consent. Когда проблем нет, я извлекаю токен с идентификатором клиента, секретом, областью действия по умолчанию и grant_type как client_credentials, как указано в документации . Когда я получаю токены без проблем, я публикую их, получая доступ к связанной модели указанного пользователя. (Обычно, если это сделано и проблем не было, я бы обновил пользователя логическим значением, чтобы он знал, что он был аутентифицирован без доступа к соответствующей модели, которая работала, но по какой-то причине не обновлялась в базе данных.)

Теперь я перенаправлен на веб-сайт, и мне просто нужно выйти из системы, чтобы обновить sh повар ie, чтобы он знал, что я аутентифицирован с помощью Microsoft Graph. Поэтому, когда я go проверяю заказы на выбранные почтовые ящики ресурса, я вижу эту информацию, но она не работает.

Когда я пытаюсь получить информацию о бронировании, я спрашиваю об этом по пользовательскому маршруту в моем Loopback среда, которая /API/bookings/:userid. На этом маршруте у меня есть следующий код для получения информации о бронировании:

'use strict';
const request = require('request');
var querystring = require('querystring');
const server = require("../server");
module.exports = function() {
    return function(req, res, next) {
        /**
         * retrieve bookings user
         */
        var AuthUser = server.models.AuthUser;
        AuthUser.findById(req.params.userid, { include: 'msauth' }, function(err, au) {
            if (err) return next(err);
            if (au == null) return next;
            console.log(au);
            if (au.msauth == null) return next;
            const data = querystring.stringify({
                "schedules": ["meetingroom@example.com", *RESOURCE_MAILBOX*],
                "startTime": {
                    "dateTime": "2020-02-20T01:00:00",
                    "timeZone": "Europe/Paris"
                },
                "endTime": {
                    "dateTime": "2020-02-29T23:00:00",
                    "timeZone": "Europe/Paris"
                }
            });
            const postOptions = {
                url: "https://graph.microsoft.com/v1.0/me/calendar/getSchedule",
                method: 'POST',
                body: data,
                headers: {
                    'Authorization': "Bearer " + au.msauth.access_token,
                    'Content-Type': 'application/json',
                    'Prefer': "outlook.timezone='Pacific Standard Time'"
                }
            }
            request(postOptions, function(err, resp, body) {
                if (err) return next(err);
                console.log(body);
                res.json(body);
            })
        });
    }
}

Здесь я сначала ищу пользователя, указанного в маршруте, и добавляю соответствующую модель с токеном доступа к получающемуся пользователю. Так что со всей информацией из поиска я могу получить информацию о бронировании, которая по какой-то причине не работает.

Так что, если кто-то знает, в чем может быть проблема, пожалуйста, дайте мне знать, или если у кого-то есть советы по подход, который я использую, всегда приветствуется.

Заранее спасибо!

1 Ответ

0 голосов
/ 27 февраля 2020

Итак, я нашел решение для того, чего хотел достичь, но мне пришлось использовать библиотеку Microsoft. Поэтому я нашел демонстрационное приложение Microsoft Graph и отредактировал то, что хотел достичь. Когда это сработало, я просто скопировал его в свой проект и отредактировал, чтобы он использовал только то, что мне было нужно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...