Расширение типа аутентификации

Обзор

NocoBase поддерживает расширение типов пользовательской аутентификации по мере необходимости. В общем пользовательская аутентификация делится на два типа: определение личности пользователя непосредственно внутри приложения NocoBase (например, вход по паролю, вход по SMS и т.п.); определение личности пользователя сторонними сервисами и отправка уведомления приложению NocoBase о результате через callbacks, например OIDC, SAML и другие методы аутентификации. Процесс аутентификации этих двух типов методов в NocoBase в общих чертах выглядит следующим образом:

Не требуются callback от третьей стороны

  1. Клиент использует NocoBase SDK для вызова интерфейса входа api.auth.signIn(), запрашивая интерфейс auth:signIn, при этом передавая идентификатор текущего аутентификатора в серверную часть через заголовок запроса X-Authenticator.
  2. Интерфейс auth:signIn перенаправляет вызов на соответствующий тип аутентификации на основе идентификатора аутентификатора в заголовке запроса, а метод validate() в зарегистрированном классе аутентификации выполняет соответствующую логическую обработку.
  3. Клиент получает пользовательскую информацию и аутентификационный токен из ответа интерфейса auth:signIn, сохраняет токен в локальном хранилище и завершает вход. Этот шаг обрабатывается SDK автоматически.

Зависит от callback-ов третьей стороны

  1. Клиент получает URL входа стороннего сервиса через собственный зарегистрированный интерфейс (например, auth:getAuthUrl), и передает информацию вроде имени приложения и идентификатора аутентификатора согласно протоколу.
  2. Выполните редирект на URL стороннего сервиса, чтобы завершить вход. Сторонний сервис вызывает callback-интерфейс приложения NocoBase (который нужно зарегистрировать самостоятельно, например auth:redirect), возвращает результат аутентификации и информацию вроде имени приложения и идентификатора аутентификатора.
  3. В методе callback-интерфейса выполните разбор параметров, чтобы получить идентификатор аутентификатора, получите соответствующий класс аутентификации через AuthManager и активно вызовите метод auth.signIn(). Метод auth.signIn() вызовет validate(), чтобы обработать логику аутентификации.
  4. После того как callback-метод получает аутентификационный токен, он редиректит обратно на страницу в клиентской части с кодом ответа 302 и передает token и идентификатор аутентификатора в параметрах URL: ?authenticator=xxx&token=yyy.

Далее мы обсудим, как зарегистрировать интерфейсы на стороне сервера и интерфейсы на стороне клиента.

Сервер

Интерфейс аутентификации

Ядро NocoBase предоставляет регистрацию и управление для расширения типов аутентификации. Основная логика обработки расширения плагина входа требует наследоваться от абстрактного класса ядра Auth и реализовать соответствующие стандартные интерфейсы.
Полное описание см. в Auth.

import { Auth } from '@nocobase/auth';

class CustomAuth extends Auth {
  set user(user) {}
  get user() {}

  async check() {}
  async signIn() {}
}

Также ядро регистрирует базовые операции ресурсов, связанные с пользовательской аутентификацией.

APIОписание
auth:checkПроверить, вошел ли пользователь
auth:signInВход
auth:signUpРегистрация
auth:signOutВыход

В большинстве случаев расширенный тип пользовательской аутентификации может использовать существующую JWT-логику для генерации учетных данных пользователя для доступа к API. Класс BaseAuth в ядре реализует базовую часть абстрактного класса Auth; см. BaseAuth. Плагины могут напрямую наследоваться от BaseAuth, чтобы снизить затраты на разработку.

import { BaseAuth } from '@nocobase/auth';

class CustomAuth extends BaseAuth {
  constructor(config: AuthConfig) {
    // Установить коллекцию пользователей
    const userCollection = config.ctx.db.getCollection('users');
    super({ ...config, userCollection });
  }

  // Реализовать логику аутентификации пользователя
  async validate() {}
}

Данные пользователя

При реализации логики пользовательской аутентификации обычно приходится обрабатывать данные пользователя. В приложении NocoBase соответствующие коллекции определены по умолчанию:

КоллекцииОписаниеПлагин
usersХранит информацию о пользователе, например email, никнейм и парольПользователи (@nocobase/plugin-users)
authenticatorsХранит информацию об аутентификаторе (сущности типа аутентификации), соответствующую типу аутентификации и конфигурацииАутентификация (@nocobase/plugin-auth)
usersAuthenticatorsСвязывает пользователей и аутентификаторы, сохраняет информацию о пользователе под соответствующим аутентификаторомАутентификация (@nocobase/plugin-auth)

Как правило, расширенные методы входа используют users и usersAuthenticators для хранения соответствующих данных. Только в особых случаях нужно добавлять новую коллекцию самостоятельно.

Основные поля usersAuthenticators:

ПолеОписание
uuidУникальный идентификатор этого типа аутентификации, например номер телефона или идентификатор пользователя стороннего сервиса
metaПоле JSON, прочая информация для сохранения
userIdID пользователя
authenticatorИмя аутентификатора (уникальный идентификатор)

Для операций запросов к пользователю и создания новых пользователей data model AuthModel для authenticators также инкапсулирует несколько методов, которые можно использовать в классе CustomAuth через this.authenticator[methodName]. Для полного API см. AuthModel.

import { AuthModel } from '@nocobase/plugin-auth';

class CustomAuth extends BaseAuth {
  async validate() {
    // ...
    const authenticator = this.authenticator as AuthModel;
    this.authenticator.findUser(); // Запросить пользователя
    this.authenticator.newUser(); // Создать нового пользователя
    this.authenticator.findOrCreateUser(); // Найти или создать нового пользователя
    // ...
  }
}

Регистрация типа аутентификации

Расширенный метод аутентификации должен быть зарегистрирован в модуле управления аутентификацией.

class CustomAuthPlugin extends Plugin {
  async load() {
    this.app.authManager.registerTypes('custom-auth-type', {
      auth: CustomAuth,
    });
  }
}

Клиент

Интерфейс пользовательской части регистрируется через интерфейс registerType, предоставляемый клиентом плагина аутентификации пользователя:

import AuthPlugin from '@nocobase/plugin-auth/client';

class CustomAuthPlugin extends Plugin {
  async load() {
    const auth = this.app.pm.get(AuthPlugin);
    auth.registerType('custom-auth-type', {
      components: {
        SignInForm, // Форма входа
        SignInButton, // Кнопка входа (сторонняя), как альтернатива форме входа
        SignUpForm, // Форма регистрации
        AdminSettingsForm, // Форма настроек администратора
      },
    });
  }
}

Форма входа

Если есть несколько аутентификаторов, они будут отображаться в виде вкладок. Заголовок вкладки — это заголовок аутентификатора, настроенного в серверной части.

Кнопка входа

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

Форма регистрации

Переход со страницы входа на страницу регистрации настраивается внутри компонента входа.

Форма настроек администратора

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

Запросы к API

Чтобы инициировать запросы к интерфейсам, связанным с пользовательской аутентификацией, на клиентской стороне, можно использовать SDK, предоставляемый NocoBase.

import { useAPIClient } from '@nocobase/client';

// Использование в компоненте
const api = useAPIClient();
api.auth.signIn(data, authenticator);

Подробные ссылки на API см. в @nocobase/sdk - Auth.