Как разграничить доступ к данным на уровне базы данных?
в базе данных созданы три роли: guest,customer и admin. В самом проекте также реализованы три варианта подключения к базе данных:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'test',
'USER': 'guest',
'PASSWORD': 'guest',
'HOST': 'localhost',
'PORT': 5432,
},
'admin': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'test',
'USER': 'admin',
'PASSWORD': 'admin',
'HOST': 'localhost',
'PORT': 5432,
},
'customer': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'test',
'USER': 'customer',
'PASSWORD': 'customer',
'HOST': 'localhost',
'PORT': 5432,
}
}
Как и где я могу менять подключение к БД в зависимости от того авторизован пользователь или нет?
Во-первых, тут вы неправильно используете термин "авторизован". Вы имеете ввиду "аутентифицирован".
Это можно сделать используя несколько ингридиентов:
- middleware - для определения, какую БД использовать в зависимости от того, аутенифицирован пользователь или нет. Это нужно, чтоб этот механизм работал при обработке веб запроса.
- threadlocal - для хранения текущей выбранной БД
- database router, который будет выбирать БД, которую нужно использовать
request_db = threading.local()
class DbRouterMiddleware(object):
def process_request(self, request):
if request.user.is_authenticated:
if request.user.username == 'admin'
db_name = 'admin'
else:
db_name = 'customer'
else:
db_name = 'default'
request_db.name = db_name
return None
def process_response( self, request, response ):
if hasattr(request_db, 'name'):
del request_db.name
return response
# django использует этот класс, чтоб определить к какой БД обращаться
# Мы тут используем значение из request_db, если оно есть, иначе 'default'
# А значение в request_db положила DbRouterMiddleware
class DatabaseRouter(object):
def _get_request_db(self ):
return getattr(request_db, 'name', 'default'):
def db_for_read( self, model, **hints ):
return self._get_request_db()
def db_for_write( self, model, **hints ):
return self._get_request_db()
Нужно сконфигурировать middleware и router в django settings:
# DbRouterMiddleware использует результат работы
# SessionMiddleware и AuthenticationMiddleware так что порядок важен
MIDDLEWARE_CLASSES = [
...
"django.contrib.sessions.middleware.SessionMiddleware",
...
"django.contrib.auth.middleware.AuthenticationMiddleware",
"path.to.my.DbRouterMiddleware"
]
...
DATABASE_ROUTERS = [DatabaseRouter]