Аутентификация в ODataDB

Аутентификация в ODataDB

Содержание

Введение

ODataDB создает конечные точки для каждого подключения, определенного в файле appsettings.

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

Для аутентификации, ODataDB меняет шаблоны на полученные значения и пытается подключиться к базе данных.

К примеру, файл appsettings.json содержит текст:

{
  "ConnectionStrings": {
    "mssql": {
      "ProviderName": "System.Data.SqlClient",
      "ConnectionString": "Data Source=.\\SQLEXPRESS;Initial Catalog=master;User ID=user;Pwd=pass"
    },
    "mssql-023": {
      "ProviderName": "System.Data.SqlClient",
      "ConnectionString": "Data Source=mssql.savetodb.com;Initial Catalog=AzureDemo100;User ID=sample02_user3;Pwd=Usr_2011#_Xls4168"
    }
  }
}

В этом примере конечные точки mssql требуют аутентификации, а точки mssql-023 - нет.

Схемы аутентификации

ODataDB поддерживает:

  • аутентификацию Basic, как определено в стандарте RFC2617
  • аутентификацию JWT

Выбрать схему можно в свойстве Auth файла appsettings.

Выбор аутентификации JWT позволяет также использовать аутентификацию Basic.

Обе схемы являются безопасными при использовании HTTPs.

Для аутентификации Basic ODataDB возвращает ошибку 401 "Unauthorized" при неавторизованных запросах любых ресурсов.

Для аутентификации JWT ODataDB возвращает ошибку 403 "Forbidden" при неавторизованных запросах только защищенных ресурсов.

HTTP и HTTPS

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

Всегда включайте протокол HTTPS и настраивайте перенаправление HTTP запросов на HTTPS.

Аутентификация пользователей

ODataDB поддерживает два способа проверки логина и пароля пользователя:

  1. с использованием логина и пароля пользователя в базе данных
  2. с использованием хранимых процедур

Первый способ используется по умолчанию. ODataDB меняет шаблоны user и pass строки подключения и пытается подключиться к базе данных.

Если подключение успешно, ODataDB загружает модель и обсуживает запросы пользователя. В противном случае, возвращается ошибка подключения.

При втором способе, ODataDB вызывает хранимую процедуру, передавая имя пользователя и пароль.

Процедура проверяет данные пользователя и возвращает пустое сообщение об ошибке для успеха или сообщение об ошибке.

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

Пример аутентификации хранимыми процедурами

Предположим, у нас есть база данных marketplace для обслуживания покупателей и продавцов.

У нас есть таблица user с необходимыми полями: id, uid, username, email, password_hash, role, seller_id.

Нам необходимо проверять данные пользователя процедурой usp_sign_in и выполнять последующие запросы от имени пользователей ролей buyer или seller, передавая в процедуры полученные идентификаторы пользователя и продавца.

Использование разных логинов для разных ролей позволяет настраивать разрешения и получать различные модели. Поэтому, покупатели будут видеть в модели только объекты для покупателей, а продавцы - объекты для продавцов.

Ниже приведен пример конфигурации:

    "marketplace": {
      "ProviderName": "MySqlConnector",
      "ConnectionString": "Server=localhost;Password=pass;User ID=user;Database=marketplace",
      "SignIn": "marketplace.usp_sign_in",
      "AuthContextParams": "auth_user_id auth_seller_id",
      "RoleUsers": {
        "auth": {
          "Username": "marketplace_auth",
          "Password": "Usr_2011#_Xls4168"
        },
        "default": {
          "Username": "marketplace_buyer",
          "Password": "Usr_2011#_Xls4168"
        },
        "buyer": {
          "Username": "marketplace_buyer",
          "Password": "Usr_2011#_Xls4168"
        },
        "seller": {
          "Username": "marketplace_seller",
          "Password": "Usr_2011#_Xls4168"
        }
      }
    },

См. полное описание полей в файле appsettings.

Ниже приведены важные замечания:

  1. SignIn содержит имя процедуры для проверки пользователей.
  2. RoleUsers содержит обязательную секцию auth с данными подключения для выполнения процедуры проверки пользователей.
  3. RoleUsers содержит обязательную секцию default с данными подключения, когда не определена роль пользователя.
  4. RoleUsers содержит секции buyer и seller с данными пользователей для ролей buyer и seller.
  5. AuthContextParams содержит имена полей, которые возвращаются процедурой проверки и должны передаваться как параметры в процедуры последующих запросов пользователя.

Ниже приведен пример хранимой процедуры, в диалекте MySQL:

DROP PROCEDURE IF EXISTS usp_sign_in;

DELIMITER //
CREATE DEFINER=marketplace_dev@localhost PROCEDURE usp_sign_in(email varchar(50), password varchar(50))
BEGIN

DECLARE user_id int;
DECLARE uid varchar(50);
DECLARE role varchar(50);
DECLARE seller_id int;
DECLARE matched tinyint;

SELECT
    u.id, u.uid, u.role, u.seller_id, CASE WHEN get_password_hashed(password, u.password_hash) = u.password_hash THEN 1 ELSE 0 END AS matched
INTO
    user_id, uid, role, seller_id, matched
FROM
    user u
WHERE
    u.email = LOWER(email) OR u.username = LOWER(email)
LIMIT 1;

SELECT
    CASE WHEN matched = 1 THEN user_id ELSE NULL END AS auth_user_id
    , CASE WHEN matched = 1 THEN uid ELSE NULL END AS uid
    , CASE WHEN matched = 1 THEN role ELSE NULL END AS role
    , CASE WHEN matched = 1 THEN seller_id ELSE NULL END AS auth_seller_id
    , CASE
        WHEN matched = 1 THEN NULL
        WHEN user_id IS NOT NULL THEN 'Password not matched'
        ELSE 'User not found'
        END AS message;
END
//

DELIMITER ;

GRANT EXECUTE ON PROCEDURE usp_sign_in TO 'marketplace_auth'@'localhost';

Обратите внимание на следующие важные моменты:

  1. Процедура должна иметь два параметра, для имени пользователя и пароля. Порядок важен. Имена - нет.
  2. Для имени пользователя должен использоваться один параметр, даже если пользователь может использовать имя или почту. Просто проверяйте оба варианта.
  3. В поле message следует вернуть пустое сообщения для успеха или сообщение об ошибке.
  4. Установите разрешение EXECUTE на процедуру проверки пользователей для пользователя, заданного в секции RoleUsers:auth.