Поделиться через


Добавление проверки подлинности пользователей в приложения TypeScript для Microsoft Graph

В этой статье описано, как добавить проверку подлинности пользователя в приложение, созданное в разделе Сборка приложений TypeScript с помощью Microsoft Graph. Затем вы используете API пользователя Microsoft Graph для получения пользователя, прошедшего проверку подлинности.

Добавление проверки подлинности пользователя

Клиентская библиотека удостоверений Azure для JavaScript предоставляет множество TokenCredential классов, реализующих потоки маркеров OAuth2. Клиентская библиотека JavaScript Microsoft Graph использует эти классы для проверки подлинности вызовов Microsoft Graph.

Настройка клиента Graph для проверки подлинности пользователей

Начните с использования DeviceCodeCredential класса , чтобы запросить маркер доступа с помощью потока кода устройства.

  1. Откройте graphHelper.ts и замените его содержимое следующим.

    import 'isomorphic-fetch';
    import {
      DeviceCodeCredential,
      DeviceCodePromptCallback,
    } from '@azure/identity';
    import { Client, PageCollection } from '@microsoft/microsoft-graph-client';
    import { User, Message } from '@microsoft/microsoft-graph-types';
    // prettier-ignore
    import { TokenCredentialAuthenticationProvider } from
      '@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials/index.js';
    
    import { AppSettings } from './appSettings.js';
    
    let _settings: AppSettings | undefined = undefined;
    let _deviceCodeCredential: DeviceCodeCredential | undefined = undefined;
    let _userClient: Client | undefined = undefined;
    
    export function initializeGraphForUserAuth(
      settings: AppSettings,
      deviceCodePrompt: DeviceCodePromptCallback,
    ) {
      // Ensure settings isn't null
      if (!settings) {
        throw new Error('Settings cannot be undefined');
      }
    
      _settings = settings;
    
      _deviceCodeCredential = new DeviceCodeCredential({
        clientId: settings.clientId,
        tenantId: settings.tenantId,
        userPromptCallback: deviceCodePrompt,
      });
    
      const authProvider = new TokenCredentialAuthenticationProvider(
        _deviceCodeCredential,
        {
          scopes: settings.graphUserScopes,
        },
      );
    
      _userClient = Client.initWithMiddleware({
        authProvider: authProvider,
      });
    }
    
  2. Замените пустую initializeGraph функцию в index.ts на следующую.

    function initializeGraph(settings: AppSettings) {
      graphHelper.initializeGraphForUserAuth(settings, (info: DeviceCodeInfo) => {
        // Display the device code message to
        // the user. This tells them
        // where to go to sign in and provides the
        // code to use.
        console.log(info.message);
      });
    }
    

Этот код объявляет два частных свойства: DeviceCodeCredential объект и Client объект . Функция initializeGraphForUserAuth создает новый экземпляр DeviceCodeCredential, а затем использует его для создания нового экземпляра Client. Каждый раз, когда вызов API выполняется к Microsoft Graph через _userClient, он использует предоставленные учетные данные для получения маркера доступа.

Тестирование DeviceCodeCredential

Затем добавьте код для получения маркера доступа из DeviceCodeCredential.

  1. Добавьте следующую функцию в graphHelper.ts.

    export async function getUserTokenAsync(): Promise<string> {
      // Ensure credential isn't undefined
      if (!_deviceCodeCredential) {
        throw new Error('Graph has not been initialized for user auth');
      }
    
      // Ensure scopes isn't undefined
      if (!_settings?.graphUserScopes) {
        throw new Error('Setting "scopes" cannot be undefined');
      }
    
      // Request token with given scopes
      const response = await _deviceCodeCredential.getToken(
        _settings?.graphUserScopes,
      );
      return response.token;
    }
    
  2. Замените пустую displayAccessTokenAsync функцию в index.ts на следующую.

    async function displayAccessTokenAsync() {
      try {
        const userToken = await graphHelper.getUserTokenAsync();
        console.log(`User token: ${userToken}`);
      } catch (err) {
        console.log(`Error getting user access token: ${err}`);
      }
    }
    
  3. Выполните следующую команду в интерфейсе командной строки в корне проекта.

    npx ts-node index.ts
    
  4. Введите 1 при появлении запроса на выбор параметра. Приложение отображает URL-адрес и код устройства.

    TypeScript Graph Tutorial
    
    [1] Display access token
    [2] List my inbox
    [3] Send mail
    [4] Make a Graph call
    [0] Exit
    
    Select an option [1...4 / 0]: 1
    To sign in, use a web browser to open the page https://microsoft.com/devicelogin and
    enter the code RK987NX32 to authenticate.
    
  5. Откройте браузер и перейдите по url-адресу. Введите предоставленный код и войдите в систему.

    Важно!

    Помните о всех существующих учетных записях Microsoft 365, которые вошли в браузер при просмотре страницы https://microsoft.com/devicelogin. Используйте функции браузера, такие как профили, гостевой режим или частный режим, чтобы проверить подлинность в качестве учетной записи, которую вы планируете использовать для тестирования.

  6. После завершения вернитесь к приложению, чтобы увидеть маркер доступа.

    Совет

    Только для проверки и отладки можно декодировать маркеры доступа пользователей (только для рабочих или учебных учетных записей) с помощью средства синтаксического анализа токенов Майкрософт в сети по адресу https://jwt.ms. Анализ маркера может оказаться полезным, если при вызове Microsoft Graph возникают ошибки маркера. Например, убедитесь, что scp утверждение в маркере содержит ожидаемые области разрешений Microsoft Graph.

Получение пользователя

Теперь, когда проверка подлинности настроена, вы можете выполнить первый вызов Microsoft API Graph. Добавьте код для получения имени и адреса электронной почты пользователя, прошедшего проверку подлинности.

  1. Откройте graphHelper.ts и добавьте следующую функцию.

    export async function getUserAsync(): Promise<User> {
      // Ensure client isn't undefined
      if (!_userClient) {
        throw new Error('Graph has not been initialized for user auth');
      }
    
      // Only request specific properties with .select()
      return _userClient
        .api('/me')
        .select(['displayName', 'mail', 'userPrincipalName'])
        .get();
    }
    
  2. Замените пустую greetUserAsync функцию в index.ts на следующую.

    async function greetUserAsync() {
      try {
        const user = await graphHelper.getUserAsync();
        console.log(`Hello, ${user?.displayName}!`);
        // For Work/school accounts, email is in mail property
        // Personal accounts, email is in userPrincipalName
        console.log(`Email: ${user?.mail ?? user?.userPrincipalName ?? ''}`);
      } catch (err) {
        console.log(`Error getting user: ${err}`);
      }
    }
    

Если вы запускаете приложение сейчас, после входа приложение приветствует вас по имени.

Hello, Megan Bowen!
Email: MeganB@contoso.com

Описание кода

Рассмотрим код в getUserAsync функции. Это всего несколько строк, но есть некоторые ключевые детали, которые следует обратить внимание.

Доступ к "мне"

Функция передается /me в _userClient.api построитель запросов, который создает запрос к API get user . Этот API доступен двумя способами:

GET /me
GET /users/{user-id}

В этом случае код вызывает конечную точку GET /me API. Эта конечная точка является ярлыком для получения пользователя, прошедшего проверку подлинности, не зная его идентификатора пользователя.

Примечание.

GET /me Так как конечная точка API получает пользователя, прошедшего проверку подлинности, она доступна только для приложений, использующих проверку подлинности пользователя. Приложения для проверки подлинности только для приложений не могут получить доступ к этой конечной точке.

Запрос определенных свойств

Функция использует select метод в запросе для указания набора необходимых ей свойств. Этот метод добавляет параметр запроса $select в вызов API.

Строго типизированный тип возвращаемого значения

Функция возвращает объект, User десериализованный из ответа JSON из API. Так как код использует select, только запрошенные свойства имеют значения в возвращаемом объекте User . Все остальные свойства имеют значения по умолчанию.

Следующее действие