Аутентификация в DBGate
Содержание
- Введение
 - Схемы аутентификации
 - HTTP и HTTPS
 - Аутентификация пользователей
 - Пример аутентификации хранимыми процедурами
 
Введение
DBGate создает конечные точки для каждого подключения, определенного в файле appsettings.
Если строки подключения содержат шаблоны user и pass, DBGate требует имя пользователя и пароль.
Для аутентификации DBGate заменяет эти шаблоны на полученные значения и пытается подключиться к базе данных.
Например, файл 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 — нет.
Схемы аутентификации
DBGate поддерживает:
- Аутентификацию Basic, как определено в стандарте RFC2617
 - Аутентификацию JWT
 
Выбор схемы аутентификации осуществляется через свойство Auth в файле appsettings.
При использовании JWT также доступна аутентификация Basic.
Обе схемы безопасны при использовании HTTPS.
Для аутентификации Basic DBGate возвращает ошибку 401 "Unauthorized" для неавторизованных запросов к любым ресурсам.
Для аутентификации JWT DBGate возвращает ошибку 403 "Forbidden" для неавторизованных запросов только к защищенным ресурсам.
HTTP и HTTPS
Не используйте DBGate по протоколу HTTP, кроме localhost, так как имена и пароли передаются в открытом виде.
Всегда включайте HTTPS и настраивайте перенаправление HTTP-запросов на HTTPS.
Аутентификация пользователей
DBGate поддерживает два способа проверки логина и пароля пользователя:
- С использованием логина и пароля пользователя в базе данных.
 - С использованием хранимых процедур.
 
Первый способ используется по умолчанию. DBGate заменяет шаблоны user и pass в строке подключения и пытается подключиться к базе данных.
Если подключение успешно, DBGate загружает модель и обрабатывает запросы пользователя. В противном случае возвращается ошибка подключения.
При втором способе DBGate вызывает хранимую процедуру, передавая имя пользователя и пароль.
Процедура проверяет данные пользователя и возвращает пустое сообщение об ошибке при успехе или сообщение об ошибке.
Этот подход позволяет управлять пользователями без создания логинов в базе данных, что удобно для веб-приложений.
Пример аутентификации хранимыми процедурами
Предположим, у нас есть база данных 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.
Обратите внимание на важные моменты:
SignInсодержит имя процедуры для проверки пользователей.RoleUsersвключает обязательную секциюauthс данными подключения для выполнения процедуры проверки пользователей.RoleUsersвключает обязательную секциюdefaultс данными подключения, когда роль пользователя не определена.RoleUsersсодержит секцииbuyerиsellerс данными пользователей для соответствующих ролей.AuthContextParamsсодержит имена полей, возвращаемых процедурой проверки, которые должны передаваться как параметры в процедуры последующих запросов пользователя.
Пример хранимой процедуры на MySQL:
DROP PROCEDURE IF EXISTS usp_sign_in; DELIMITER // CREATE DEFINER=marketplace_dev@localhostPROCEDURE usp_sign_in(email varchar(50),passwordvarchar(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';
Обратите внимание на следующие важные моменты:
- Процедура должна принимать два параметра для имени пользователя и пароля. Порядок важен, но имена — нет.
 - Для имени пользователя должен использоваться один параметр, даже если пользователь может использовать имя или почту. Проверяйте оба варианта.
 - В поле 
messageследует вернуть пустое сообщение для успеха или сообщение об ошибке. - Установите разрешение 
EXECUTEна процедуру проверки пользователей для пользователя, указанного в секцииRoleUsers:auth.