Проблема:
Я создаю 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);
})
});
}
}
Здесь я сначала ищу пользователя, указанного в маршруте, и добавляю соответствующую модель с токеном доступа к получающемуся пользователю. Так что со всей информацией из поиска я могу получить информацию о бронировании, которая по какой-то причине не работает.
Так что, если кто-то знает, в чем может быть проблема, пожалуйста, дайте мне знать, или если у кого-то есть советы по подход, который я использую, всегда приветствуется.
Заранее спасибо!