Office 365. Пример работы с Microsoft Graph API в Angular5 с помощью ADAL JS. ADAL JS vs MSAL JS
В прошлый раз мы обсудили механизм авторизации для работы с Office 365 API (в частности с Microsoft Graph API):
- при каждом вызове API нужно передать token. Token имеет ограниченный срок жизни
- token выдает сервис Microsoft, так называемый «Azure AD Authorization Endpoint»
- получить token можно без серверной части используя только JavaScript в браузере. Для этого Microsoft сделал JavaScript библиотеку ADAL JS, которая упрощает коммуникацию с «Azure AD Authorization Endpoint» для получения token.
Тогда мы сделали простую статичную HTML-страницу, на которой наш vanilla JavaScript делал запрос к Microsoft Graph API и отображал список писем из Office 365. В данной заметке разовьем пример и сделаем тоже самое на Angular5.
Также поговорим о различиях рабочих (Work or school account) и персональных (Personal Account) аккаунтов при использовании Office 365 API.
Пример на GitHab.
Будем считать, что вы знакомы с предыдущей статьёй, понимаете процесс получения и использования token, уже зарегистрировали приложение в Azure, получили Application ID.
ADAL JS и MSAL JS
У Microsoft есть два вида аккаунтов:
— Work or school Account
— Personal Account
Work or school account создается (и удаляется) администратором компании, которая купила подписку Office 365. Сотрудники используют его, например, для подключения к корпоративной почте, SharePoint, OneDrive.
Personal Account создаете вы сами, используется для подключения к персональным сервисам, например личному OneDrive.
Более подробно про Work и Personal аккаунты можно почитать тут «Understanding Microsoft Work And Personal Accounts».
Office 365 API (например Microsoft Graph API) имеет разную поддержку для персональных и рабочих аккаунтов. Например, работать с почтой могут и Work account и Personal account, но не существует персонального SharePoint (а следовательно, и API SharePoint для Personal account).
Мы уже знаем, что token для вызовов API выдает «Azure AD Authorization Endpoint». Точек авторизации существует 2:
- Authorization Endpoint
Выдает токены только для Work Account-ов.
При логине пользователь отправляется на
https: //login.microsoftonline.com/common/oauth2/authorize? client_id=… - Authorization Endpoint v2.0
Выдает токены как для Work так и для Personal Account-ов
При логине пользователь отправляется на
https: //login.microsoftonline.com/common/oauth2/v2.0/authorize?
client_id=…
Зачем тогда вообще нужен «Authorization Endpoint»? Особенность заключается в том, что «Authorization Endpoint v2.0» выдаст токен только для тех возможностей API которые есть и для Work и для Personal аккаунтов. Т.е. используя Endpoint v2.0 и Work account вы сможете получить доступ к почте, но не будет доступа к API SharePoint (подробнее о том какие API поддерживает Endpoint v2.0 см в ссылках в конце).
В настоящее время v2.0 endpoint не работает с приложениями, которые зарегистрированы в корпоративном Azure портале (такую регистрацию мы делали в прошлой заметке), нужно использовать отдельный Microsoft Application Registration Portal.
Microsoft обещает в будущем расширить возможности v2.0 endpoint, и обеспечить поддержку приложений, зарегистрированных в корпоративном Azure портале — v2.0 endpoint сможет выдать для них токены. А пока, для корпоративных приложений, Microsoft рекомендует использовать «Authorization Endpoint»:
If your application only needs to support Microsoft work and school accounts, don’t use the v2.0 endpoint
ADAL JS работает с «Authorization Endpoint», MSAL JS с v2.0 endpoint. В данной заметке мы будем использовать Authorization Endpoint первой версии и соответственно ADAL JS.
Angular 5 и ADAL JS
Нам понадобится установленный Node.js, npm, и Angular CLI — утилита которая помогает создавать и собирать Angular проекты. Весь процесс хорошо описан в Angular QuickStart.
Сделаем новый проект:
ng new angular5-office365-adal-example
Не существует официальных (от Microsoft) TypeScript d.ts описаний для Adal.js. Несколько вариантов использования Adal.js в Angular 5:
- Не использовать d.ts описания, объявить объект AuthenticationContext (из Adal.js) как глобальный any и писать нетипизированный код как на обычном JavaScript
- Самому сделать d.ts описание
- Воспользоваться проектом adal-angular5, который является калькой оригинального adal-angular.js для AngularJS от Microsoft (Adal js)
- Есть проекты, в которых Adal js полностью переписан на TypeScript (adal-ts, adal-typescript)
- Воспользоваться готовым d.ts описанием.
5 вариант выглядит самым простым и удобным: используется оригинальный Adal.js от Microsoft и с помощью d.ts описания добавляете intellisense и проверки при сборке.
Установим проверенные d.ts описания для Adal.js (https://www.npmjs.com/package/@types/adal). Находясь в папке проекта:
npm install --save @types/adal
У нас пример тестовый, поэтому сделаем его максимально простым: будем подключаться к Microsoft Graph API прямо в AppComponent.
В файле app.component.ts импортируем HttpClient и adal
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { } from 'adal'; // без этого приложение будет собираться, но будут сообщения об ошибках
В app.module.ts подключим HttpClientModule
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http'; //<- ADD
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpClientModule //<- ADD
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Подключим js-библиотеку к странице
Дальше будет точно такой же код как в прошлом примере на JS.
В ngOnInit проверим авторизован пользователь или нет, если не авторизован или token протух отправим пользователя на страницу регистрации.
let config: adal.Config = {
tenant: 'igtit.onmicrosoft.com',
clientId: '21XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX',
postLogoutRedirectUri: window.location.origin,
endpoints: {
graphApiUri: "https://graph.microsoft.com",
},
cacheLocation: "localStorage",
redirectUri: ''
};
let authContext = new AuthenticationContext(config);
let isCallback = authContext.isCallback(window.location.hash);
authContext.handleWindowCallback();
if (isCallback && !authContext.getLoginError()) {
window.location.href = (authContext)._getItem((authContext).CONSTANTS.STORAGE.LOGIN_REQUEST);
}
// check if user need to login
let user = authContext.getCachedUser();
let token = authContext.getCachedToken(config.clientId);
if (!user || !token) {
authContext.login();
}
Теперь можно использовать token для вызова Microsoft Graph API
authContext.acquireToken(config.endpoints.graphApiUri, (error, token) => {
// call Microsoft Graph API with token
let url = config.endpoints.graphApiUri + "/v1.0/me/messages";
this.http.get(url, {
headers: {
"Authorization": "Bearer " + token
}
}).subscribe(mgs => this.messages = (mgs).value);
});
Полный пример на GitHab.
Ссылки
Active Directory Authentication Library (ADAL) for JavaScript
Microsoft Authentication Library Preview for JavaScript (MSAL.js)
Should I use the v2.0 endpoint?
What’s different about the v2.0 endpoint?
Understanding Microsoft Work And Personal Accounts