Как реализовать JWT-аутентификацию с динамической базой данных в Django? (Таблица пользователей находится в каждой базе данных, она не центральная)

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

Вот установка:

  • JWT Authentication используется для приложения.
  • Центральный Django-сервер обрабатывает запросы на аутентификацию, но должен динамически подключаться к базе данных клиента на основе информации, предоставленной в JWT-токене.
  • Токен employee_id хранится в базе данных каждого клиента, а не в центральной базе данных Django.
  • Строка подключения к базе данных клиента включается в полезную нагрузку JWT-токена.

Моя реализация:

Я создал пользовательский класс JWTAuthentication, в котором:

  1. Token Validation: JWT-токен проверяется.
  2. Подключение к базе данных: На основе полезной нагрузки токена я динамически подключаюсь к базе данных клиента, используя строку подключения, указанную в токене.
  3. Проверка пользователя: Я получаю пользователя из базы данных клиента, используя employee_id в токене, и проверяю, активен ли пользователь.

Вот упрощенная версия моего JWTAuthentication класса:

from rest_framework import authentication
from rest_framework.request import Request
from .models import TokenUser
from .settings import api_settings
from .tokens import Token
from .exceptions import AuthenticationFailed, InvalidToken
import pymssql

class JWTAuthentication(authentication.BaseAuthentication):
    def authenticate(self, request: Request):
        header = self.get_header(request)
        if header is None:
            return None

        raw_token = self.get_raw_token(header)
        if raw_token is None:
            return None

        validated_token = self.get_validated_token(raw_token)
        return self.get_user(validated_token), validated_token

    def get_user(self, validated_token: Token):
        employee_id = validated_token.get(api_settings.USER_ID_CLAIM)
        conn_string = validated_token.get('conn')
        role = validated_token.get('role')

        if not employee_id:
            raise InvalidToken("Token contained no recognizable user identification")

        if role == 0:
            # Local database user fetching logic
            try:
                user = self.user_model.objects.get(**{api_settings.USER_ID_FIELD: employee_id})
                if not user.is_active:
                    raise AuthenticationFailed("User is inactive", code="user_inactive")
                return user
            except self.user_model.DoesNotExist:
                raise AuthenticationFailed("User not found", code="user_not_found")
        else:
            # External database connection logic
            if not conn_string:
                raise InvalidToken("Token contained no connection string")

            def reconnect(conn_string):
                conn_details = conn_string.split(':')
                server, database, username, password = conn_details[1:5]
                return pymssql.connect(server=server, user=username, password=password, database=database)

            with reconnect(conn_string) as connection:
                cursor = connection.cursor()
                cursor.execute("""
                    SELECT [btEmpIsActive]
                    FROM [tblMstEmployee]
                    WHERE [inEmpId] = %s
                """, [employee_id])

                row = cursor.fetchone()
                if not row:
                    raise AuthenticationFailed("User not found in the external database", code="user_not_found")

                is_active = row[0]
                if not is_active:
                    raise AuthenticationFailed("User is inactive in the external database", code="user_inactive")

            return TokenUser(token=validated_token)

Мои вопросы:

  1. Безопасен ли этот подход? :

    • Подключаясь динамически к клиентским базам данных, подвергаю ли я себя каким-либо значительным рискам безопасности?
    • Как я могу гарантировать, что строка подключения не будет подделана в токене?
  2. Обработка верификации пользователя:

    • В настоящее время я строго проверяю employee_id и активный статус пользователя. Есть ли безопасный способ обойти или изменить эту проверку при необходимости?
    • Каким передовым методам следует следовать для безопасного управления идентификацией пользователей в нескольких базах данных?
  3. Альтернативные подходы:

    • Существуют ли альтернативные методы обработки аутентификации, когда таблица пользователей находится не в центральной базе данных, а распределена по динамическим, специфическим для клиента базам данных?
    • Может ли использование архитектуры микросервисов с выделенным сервисом аутентификации быть лучшим подходом?

Дополнительная информация:

  • Django Version: 3.x
  • База данных: MSSQL (используется pymssql для соединений)
  • Аутентификация: JWT (с помощью REST-фреймворка Django)

Я открыт для предложений или лучших практик, которые могут сделать эту настройку более безопасной и эффективной. Заранее спасибо!

Я хочу построить систему аутентификации, которая удовлетворит мою ситуацию, когда нет одной центральной базы данных, а есть несколько клиентских баз данных на сервере

Вернуться на верх