Задавайте вопросы, мы ответим
Вы не зашли.
Сегодня столкнулся с проблемой, связанной с CURRENT_USER.
Он, оказывается, в процедурах возвращает данные пользователя, который определил объект.
Очень весело, учитывая то, что большая часть процедур определены под root и проверяют права по имени пользователя...
Within a stored program or view, CURRENT_USER() returns the account for the user who defined the object (as given by its DEFINER value). This applies to stored programs as of MySQL 5.0.10 and to views as of MySQL 5.0.24. (For older versions, CURRENT_USER() returns the account for the object's invoker.) For stored procedures and functions and views defined with the SQL SECURITY INVOKER characteristic, CURRENT_USER() returns the object's invoker.
Проблема в том, что просто заменить на USER() я не могу, т.к. у меня ключи в таблицах - это User/Host (как в mysql.user).
Мне нужна запись в таблице, соответствующая клиенту, вызвавшему объект.
А USER() возвращает хост, с которого клиент подключился.
Т.е. есть:
mysql> select CURRENT_USER();; +----------------+ | CURRENT_USER() | +----------------+ | root@% | +----------------+ mysql> select USER();; +----------------+ | USER() | +----------------+ | root@localhost | +----------------+
Есть ли какая-то альтернатива CURRENT_USER(), которая возвращает данные вызвавшего объект?
Отредактированно Артём Н. (20.05.2010 21:24:52)
Неактивен
Нету, но и смысла использовать CURRENT_USER нету. Не нужно смешивать
пользователей БД и пользователей Вашего приложения. Это разные сущности,
и они должны обрабатываться по разному. Кстати, в Вашем случае, если Вы
все-таки хотите смешивать эти сущности, нужно поступить так, как подразу-
мевается структурой СУБД — давать права на запуск процедуры тому, кто
может ее запускать, а не проверять пользователя внутри.
Неактивен
Не нужно смешивать пользователей БД и пользователей Вашего приложения.
Мне от этого никуда не деться, поскольку, у меня не web-приложение.
Каждый пользователь должен иметь свой аккаунт в СУБД.
Кстати, в Вашем случае, если Вы
все-таки хотите смешивать эти сущности, нужно поступить так, как подразу-
мевается структурой СУБД — давать права на запуск процедуры тому, кто
может ее запускать, а не проверять пользователя внутри.
Это не очень хорошая идея, хотя бы потому, что администратору приложения придётся давать права на БД mysql.
Плюс, это сложно реализуется. Гораздо проще иметь таблицу "высокоуровневых" прав, чем давать права на запуск процедур. Например, у меня есть право на заведение договора. Договор заводится процедурой. Права на запуск - как-то не очень. Плюс, к тому же, в зависимости от наличия других прав, процедура может изменять своё поведение.
А возможно ли как-то реализовать функционал CURRENT_USER() средствами SQL?
Неактивен
Во так делать, по ходу, очень криво:
CREATE DEFINER = 'root'@'%' PROCEDURE GetCurUser(OUT user_name CHAR(16), OUT host_name CHAR(60)) READS SQL DATA SQL SECURITY INVOKER COMMENT 'Получение текущего пользователя' BEGIN select substring_index(user(),"@", 1), substring_index(user(),"@", -1) into user_name, host_name; #!!! Костыль. select Host into host_name from mysql.user where User = user_name; END;
А как сделать не криво?
Не думаю, что сам подход надо менять. Проверять права высокого уровня в процедурах - вполне логично.
Неактивен
Даже в не-web-приложении не нужно смешивать
Вот тут Вам нужно определиться — либо Вам нужны высокоуровневые права, либо
низкоуровневые. Ваша проблема в том, что Вы не записали это на бумажке и не
поставили под этим подпись «так я буду делать, и никак иначе». Вы пытаетесь
сделать смесь высокоуровневого и низкоуровневого. И от этого страдаете.
Либо высокого уровня — независимые логины-пароли от БД — и тогда проверяете
в процедурах, либо низкого уровня — и тогда доверяете проверку прав MySQL.
Неактивен
Вот тут Вам нужно определиться — либо Вам нужны высокоуровневые права, либо
низкоуровневые. Ваша проблема в том, что Вы не записали это на бумажке и не
поставили под этим подпись «так я буду делать, и никак иначе». Вы пытаетесь
сделать смесь высокоуровневого и низкоуровневого. И от этого страдаете.
Мне нужно и то, и это.
Либо высокого уровня — независимые логины-пароли от БД — и тогда проверяете
в процедурах, либо низкого уровня — и тогда доверяете проверку прав MySQL.
А как вы мне предлагаете делать запросы?
Ведь запросы бывают разные. Определить их список и упрятать в процедуры - ещё более извращённый вариант. Сложный и плохо расширяемый.
К тому же, зачем дублировать таблицу mysql.user в своей БД?
В чём минусы использования системных аккаунтов? Они нагружают систему?
Сложно администрируются? Загромождают БД?
Плюсов много. Хотя-бы встроенный механизм прав. К чему делать то, что уже реализовано?
Плюс, всё нормально работает, если не считать этой функции. Кстати, раньше её поведение было иное... Мда, "обратная совместимость". :-\
Неактивен
Хорошо, Вы решили использовать встроенную систему прав MySQL. Используйте ее.
Те, кто не может запускать процедуру — не могут ее запускать. Проверять внутри
ничего не надо. Если функция может выполнять два разных действия в зависимости
от того, есть ли у пользователя права, это должны быть две разные функции.
Неактивен
Хорошо, Вы решили использовать встроенную систему прав MySQL. Используйте ее.
Те, кто не может запускать процедуру — не могут ее запускать. Проверять внутри
ничего не надо.
Да, я думал об этом. В принципе, переделать возможно. И достаточно просто.
У меня есть таблица с правами группы.
Вместо проверки прав группы в процедуре, добавить в триггер установку прав на запуск процедур.
Но, во-первых, это не решит проблему окончательно. Поскольку, ключи в таблице с пользовательской информацией - Host/User.
Например, пользователь меняет договор. Мне нужно занести ФИО в поле VARCHAR.
ФИО берётся из таблицы user_data, где ключ Host/User. Работать, очевидно, с таким поведением функции, это не будет.
Во-вторых, я не вижу в чём ущербность моего подхода? Есть ли что-то такое, что позволило бы мне уверенно сказать: "Нет. Так делать нельзя. Это абсолютно исключено."?
Если функция может выполнять два разных действия в зависимости
от того, есть ли у пользователя права, это должны быть две разные функции.
Я понимаю. Но вот, например, процедура добавляет договор.
Она проверяет права на добавление и изменение договора.
Если есть права на изменение, пропускается проверка дат.
Код процедуры немаленький. Стоит ли делать две процедуры, в таком случае?
Да, конечно, возможно сделать "накладку", которая будет проверять даты и отдельно на неё выдавать права.
Но стоит ли оно того? Ради чего?
Неактивен
Уху, я бы действительно не привязывался к правам MySQL
Неактивен
Почему?
Неактивен
Ну, потому что у нее одно лишь предназначение — ограничивать права
доступа пользователей MySQL. С точки зрения приложения — это обычно
не достаточно гибкие права. Смешивать не стоит, поэтому в приложении
имеет смысл делать свои права доступа.
Неактивен
Но, в таком случае, мне придётся делать свою реализацию работы с пользователями.
Почти аналогичную сделанной в MySQL.
А для чего? Что плохо сейчас?
Отредактированно Артём Н. (26.05.2010 17:27:24)
Неактивен
Плохо то, что встроенная Вас не устраивает, а другую Вы писать не хотите —
вот и мучаетесь, не зная, как поступить
В любом случае, это вопрос предпочтений. Предлагаю тему закрыть, т.к. она
перестала нести полезную нагрузку приблизительно после первого ответа
Неактивен
Плохо то, что встроенная Вас не устраивает, а другую Вы писать не хотите —
вот и мучаетесь, не зная, как поступить
Угу.
Встроенную я использую только для:
1.) Идентификации и авторизации пользователей.
2.) Полного запрета записи в БД.
3.) Ну ещё права на справочники некоторым даю.
Чтобы логику клиента сильнее не усложнять.
А все остальные права - "высокоуровневые". Чем же плоха такая организация?
Помимо, одной функции, которая работает не так, как я предполагал?
Я не могу понять.
В любом случае, это вопрос предпочтений. Предлагаю тему закрыть, т.к. она
перестала нести полезную нагрузку приблизительно после первого ответа
Вы ошибаетесь. Сейчас я решаю стоит переделывать или нет.
Неактивен
Ну, что-то переделывать прийдется безусловно, т.к. функция для Вас
не работает, и альтернативы нету
Неактивен
#!!! Костыль. select Host into host_name from mysql.user where User = user_name;
Что плохого в такой схеме если, теоретически, удалось с успехом избавиться от костыля?
Неактивен
Можете мне ответить на следующую три вопроса:
1. Какие у меня могут быть конкретные проблемы, при такой организации прав,
которая у меня сейчас?
2. Какие могут быть проблемы, при использовании прав на процедуры?
3. В чём лучше и в чём хуже второе первого?
Неактивен
Хм... Хотя, сейчас столкнулся с проблемами, при создании временных таблиц...
Думаю, что есть смысл в правах на процедуры...
Но, помимо этого?
Отредактированно Артём Н. (30.05.2010 16:08:21)
Неактивен
Проблемы будут не у Вас, а у человека, который будет этот код поддерживать.
Поддерживать что-то консистентное в одном месте проще, чем поддерживать
полумеры в двух местах, да еще и без четко оговоренных принципов, по которым
выбирается та или иная полумера.
Неактивен
Учитывая то, что поддерживать придётся, скорее всего, мне - у меня...
Ну, в таком случае, есть два варианта:
1. Использовать стандартный механизм управления пользователями и права на выполнение процедур.
2. Реализовать сходный со стандартным механизм.
В первом - минусы:
1. Связка со стандартным механизмом (мне надо ещё хранить доп. данные пользователя, к примеру, ФИО).
Т.е. не решается проблема с этой функцией.
2. Права на процедуры. Их, наверное, сложнее администрировать. Права на выполнение неочевидны.
3. Большое число пользовательских аккаунтов в СУБД.
Во втором минусы:
1. Самостоятельная реализация механизма.
2. Низкая гибкость, по сравнению со стандартным.
К примеру, стандартный механизм может реализовывать ограничения по ресурсам (ну, может когда-то будет, я на это надеюсь). А реализовать это самостоятельно - задача уже нетривиальная и плохо разрешимая.
Так как лучше сделать, в моём случае?
Неактивен
Собтвенная реализация на MySQL грозит оказаться слишком трудоёмкой.
На мой взгляд, на уровне MySQL стоит как можно меньше кода, т.к. для подобных задач SQL очень неудобен и уступает большинству современных языков.
Поэтому права - либо на уровне встроенного механизма MySQL (процедуры можно делать с SQL_SECURITY INVOKER), либо вообще на приложении-клиенте.
Кстати (спрашиваю чисто ради интереса). Зачем Вам вообще столько кода в MySQL? (Просто единственный широко известный случай, когда использование хранимой процедуры оправдано - это разбор денормализованной таблицы курсором; и то только ради скорости).
Неактивен
Поэтому права - либо на уровне встроенного механизма MySQL (процедуры можно делать с SQL_SECURITY INVOKER)
Тогда придётся устанавливать права на таблицы. К примеру, в этом случае, нельзя проверить даты и, вообще, любые вводимые данные.
Или ограничить доступ только определёнными строками.
либо вообще на приложении-клиенте.
o.O Это точно - не вариант. Получается, что каждый может делать всё, что захочет.
Кстати (спрашиваю чисто ради интереса). Зачем Вам вообще столько кода в MySQL? (Просто единственный широко известный случай, когда использование хранимой процедуры оправдано - это разбор денормализованной таблицы курсором; и то только ради скорости).
Ну, во-первых, нужно многопользовательское приложение.
То, что было до этого, мне не понравилось.
Логины/пароли хранились в своей таблице, незашифрованными.
Каждому открыт доступ. Привилегии всем даны. Короче, сплошная "демократия".
Плюс, работа через ODBC. И клиент на том же разделе (причём расшаренном), что и БД. Все заходили в клиент под администратором.
Я решил такую халтуру не делать, а сделать, более ли менее нормально.
Во-вторых, требования слегка изменились. Пользователям всё позапрещать.
Даты проверять на проставление "задним числом". Действия протоколировать.
(Ещё и откат делать, но, нафиг, основное-то сделать бы).
В-третьих, спрашивали про "второй офис" и про web-интерфейс. На будущее.
А, если есть централизованная БД...
К тому же, в случае с web-интерфейсом, зачем ограничивать работу только им и всё делать с нуля? Пусть и клиенты с той же БД работают...
В общем, я подумал и решил сделать клиент потоньше, а сервер потолще...
Разве это плохо - переложить всё на сервер?
Неактивен
Разве это плохо - переложить всё на сервер?
Да нет, не плохо.. Просто на SQL писать замучаетесь. Прокладку бы Вам какую-нибудь на сервере.. (в смысле, чтоб не голый MySQL). Но это уже Вам виднее.
Зато будете редким человеком, кто отважился логику приложения реализовывать на MySQL
Неактивен
Да нет, не плохо.. Просто на SQL писать замучаетесь. Прокладку бы Вам какую-нибудь на сервере.. (в смысле, чтоб не голый MySQL). Но это уже Вам виднее.
Думал. Решил отказаться. Для "прокладки" нужно думать о протоколе.
И ещё проблем больше.
Зато будете редким человеком, кто отважился логику приложения реализовывать на MySQL
Мне нужно это читать, как "редкий дурак"?
Вообще, у меня не ахти какое сложное приложение.
Вышло всего-лишь на ~3500 строк. И я не единственный, кто делает логику на SQL.
К тому же, тот SQL, это обычный, Тьюринг-полный язык. Что такого?
Меня больше волнует клиент, а не сервер.
С сервером уже почти все проблемы решены.
Кстати, думаю, что авторизацию реализовать, "как в MySQL" не очень сложно.
Только, наверное, это будет изобретением велосипеда.
Насчёт, связки со стандартным механизмом я думал.
У меня в ключ входит Host. А нафиг мне Host, в принципе?
Неактивен