Table of Contents

Авторизация в TypeScript/Angular

ВНИМАНИЕ: применяемость токена входа истекает через 10 минут после его создания. Для продолжения работы нужно использовать токен обновления.

Создание Http-клиента

// В модуле
// Импортируем класс клиента
import { HttpClient, HttpHeaders } from "@angular/common/http";

// Получаем адрес сервера
export const polynomWebApiAddress = "http://localhost:5000";

export function url(value: string, customApiVersion?: number): string {
  const host = polynomWebApiAddress;
  if (host) {
    const defaultVersion = 1;
    const version = customApiVersion ? customApiVersion : defaultVersion;

    return `${host}/api/v${version}${value}`;
  }

  return value;
}

// Объявить
export const POLYNOM_STORAGE_ID = "polynom-storage-id";
export const POLYNOM_ACCESS_TOKEN = "polynom-access-token";
export const POLYNOM_REFRESH_TOKEN = "polynom-refresh-token";
// В классе

// В конструкторе получаем экземпляр класса HttpClient
constructor(private readonly _http: HttpClient) { }

Получение списка зарегистрированных хранилищ

Определение IStorageDefinition

export type IStorageDefinition = {
  storageId: string;
  displayName: string;
};

Запрос и чтение ответа:

/*Возвращает данные пользователя*/
this._http
  .get<IStorageDefinition[]>(url("/login/storage-definitions"))
  .pipe(take(1))
  .subscribe({
    next: (response) => {
      // Выбрать нужное хранилище из списка
    },
    error: (err) => {
      // Обработка ошибки
    },
  });

Вход

Определение SignInRequest

// Тип клиента API.
export enum ClientTypes {
  // Нет типа.
  None = 0,

  // Клиент.
  Client = 8,

  // Конвертер.
  Importer = 16,

  // Редактор.
  Editor = 32,

  // Администратор.
  Administrator = 64,
}

export type ISignInRequest = {
  // Идентификатор хранилища
  storageId: string;

  // Имя пользователя ПОЛИНОМ:MDM
  login?: string;

  // Пароль
  password?: string;

  // Пароль
  moduleName?: string;

  // Указывает тип клиента.
  clientType?: ClientTypes;
};

Определение AuthResponse

export type IAuthResponse = {
  // Токен доступа.
  access_token: string;

  // Тип токена доступа.
  token_type: string;

  // Срок жизни токена доступа. (сек.)
  expires_in: number;

  // Токен обновления токена доступа.
  refresh_token: string;
};

Запрос и чтение ответа:

const request: ISignInRequest = {
  login: username,
  password: password,
  storageId: storageId,
  clientType: ClientType.Client,
};

this._http
  .post<IAuthResponse>(url("/login/sign-in"), request)
  .pipe(take(1))
  .subscribe({
    next: (response) => {
      // Сохранить полученные ключи и идентификтаор хранилища для использования в запросах
      const storage: Storage = window.localStorage;
      storage.setItem(POLYNOM_STORAGE_ID, request.storageId);
      storage.setItem(POLYNOM_ACCESS_TOKEN, response.access_token);
      storage.setItem(POLYNOM_REFRESH_TOKEN, response.refresh_token);
    },
    error: (err) => {
      // Обработка ошибки
    },
  });

Использование токена в запросах к API

Чтобы отправлять запросы web-серверу ПОЛИНОМ:MDM, нужно добавить полученный ранее токен доступа и идентифмкатор хранилища в заголовок запроса.

import { HttpHeaders, HttpInterceptorFn } from "@angular/common/http";

export const jwtInterceptor: HttpInterceptorFn = (request, next) => {
  const storage: Storage = window.localStorage;

  // Получаем токен авторизации из хранилища
  const polynomAccessToken = storage.getItem(POLYNOM_ACCESS_TOKEN);
  if (polynomAccessToken) {
    // Получаем идентификатор хранилища ПОЛИНОМ:MDM
    const polynomStorageId = storage.getItem(POLYNOM_STORAGE_ID);
    if (!polynomStorageId) {
      return next(request);
    }

    const clonedRequest = request.clone({
      headers: new HttpHeaders({
        "X-Polynom-Storage-Id": polynomStorageId,
        Authorization: `Bearer ${polynomAccessToken}`,
      }),
    });

    return next(clonedRequest);
  }

  return next(request);
};

Обновление токена входа

Запрос и чтение ответа:

const storage: Storage = window.localStorage;

// Получаем идентификатор хранилища ПОЛИНОМ:MDM
const polynomStorageId = storage.getItem(POLYNOM_STORAGE_ID);
if (!polynomStorageId) {
  return;
}

// Получаем ключ авторизации из хранилища
const polynomAccessToken = storage.getItem(POLYNOM_ACCESS_TOKEN);
if (!polynomAccessToken) {
  return;
}

// Получаем ключ обновления ключа авторизации из хранилища
const polynomRefreshToken = storage.getItem(POLYNOM_REFRESH_TOKEN);
if (!polynomRefreshToken) {
  return;
}

let header = new HttpHeaders({
  "Content-Type": "text/plain",
  "X-Polynom-Storage-Id": polynomStorageId,
  Authorization: `Bearer ${polynomAccessToken}`,
});

this._http
  .patch<IAuthResponse>(url("/login/update-token"), polynomRefreshToken, {
    headers: header,
  })
  .pipe(take(1))
  .subscribe({
    next: (response) => {
      // Сохранить полученные ключи и идентификатор хранилища для использования в запросах
      const storage: Storage = window.localStorage;
      storage.setItem(POLYNOM_ACCESS_TOKEN, response.access_token);
      storage.setItem(POLYNOM_REFRESH_TOKEN, response.refresh_token);
    },
    error: (err) => {
      // Обработка ошибки
    },
  });

Выход

Запрос и чтение ответа:

this._http
  .delete<void>(url("/login/sign-out")
  .pipe(take(1))
  .subscribe({
    next: () => {
      // Сохранить полученные ключи и идентификатор хранилища для использования в запросах
      const storage: Storage = window.localStorage;
      storage.removeItem(POLYNOM_STORAGE_ID);
      storage.removeItem(POLYNOM_ACCESS_TOKEN);
      storage.removeItem(POLYNOM_REFRESH_TOKEN);
    },
    error: (err) => {
      // Обработка ошибки
    },
  });

Ссылки