Comments 103
Статья хорошая, особенно хорошо, что примеры кода есть, а не только теория.
Но… я предвижу наплыв статей на тему разделения прав доступа в веб-приложениях ;))
Но… я предвижу наплыв статей на тему разделения прав доступа в веб-приложениях ;))
Почитаем-с, спасибо.
Спасибо, статья требует детального изучения :) Вопрос очень актуальный для веб-приложений.
Интересно.
А что скажут профи по варианту хранения всех прав в сессии. Т.е. зашел на сайт/страницу пользователь, создали сессию, сделали выборку по правам и в нужном виде закинули их массивом в сессию.
Авторизовался, обновили права.
А что скажут профи по варианту хранения всех прав в сессии. Т.е. зашел на сайт/страницу пользователь, создали сессию, сделали выборку по правам и в нужном виде закинули их массивом в сессию.
Авторизовался, обновили права.
Я не профи, но внесу такое замечание: что, если права пользователя изменились во время действия одной сессии?
Это не проблема никакая, права мы получаем из массива $_SESSION, а пишем и достаем их через класс работы с правами, соответственно при изменении мы должны записать в БД, тогда же изменения можем внести в $_SESSION, ну а когда достаем — и так все понятно.
Пользователей много, а учитывая разветвленность системы прав задача «выявить всех пользователей которых затронет это изменение и обновить им сессию» становится не такой уж простой. И еще надо предусмотреть возможность получения идентификатора сессии для каждого пользователя.
если у вас настолько сложные права и так часто к ним обращаетесь, то memcache вам в помощь.
Действительно — не подумал я както о смене прав для целой группы, это хорошо только для прав конкретного пользователя.
права для конкретного пользователя — это мне кажется редкость в любой системе.
Ну тут все зависит от реализации. Если как примерно тут, то конкретному пользователю выдаются права на изменение своих ранее-созданных материалов. Опять же из некоторых разделов возможно нужно поставить запрет даже на удаление материала создателю, оставить право только администратору…
Хотя и такие моменты можно реализовать иначе, например добавлять группу owner и прописывать в ней права для различных типов материалов, а ее проверять по $uid в материале.
В общем тут долго можно обсуждать )))
Хотя и такие моменты можно реализовать иначе, например добавлять группу owner и прописывать в ней права для различных типов материалов, а ее проверять по $uid в материале.
В общем тут долго можно обсуждать )))
Принудительно обновить всем сессию – вполне рабочий вариант.
Выше предложен вариант кэширования, вот его и сбрасываем.
Выше предложен вариант кэширования, вот его и сбрасываем.
в догонку. для более удобной и правильной работы, можно весь функционал для получения и работы с правами через сессию запихать в отдельный класс
class Session_Rights extends Rights
или же прямо в Rights добавить флаг register_session: boolean;
class Session_Rights extends Rights
или же прямо в Rights добавить флаг register_session: boolean;
Спасибо за пост!
Как-то для организации разграничения прав доступа к отдельным участкам сайта использовали простую схему rwx — три численных записи о необходимом уровне доступа пользователя для выполнения того или иного действия с форумом/темой. Соответственно, каждому пользователю давался по умолчанию какой-то один уровень доступа. Разумеется, была таблица модерирования — модификаторы уровня доступа пользователя к конкретному форуму/теме.
Как-то для организации разграничения прав доступа к отдельным участкам сайта использовали простую схему rwx — три численных записи о необходимом уровне доступа пользователя для выполнения того или иного действия с форумом/темой. Соответственно, каждому пользователю давался по умолчанию какой-то один уровень доступа. Разумеется, была таблица модерирования — модификаторы уровня доступа пользователя к конкретному форуму/теме.
Хороший топик.
Также, для глубокого понимания темы и концепции ACL с доскональным объяснением отдельных моментов и проблем, советую почитать вот эту статью про phpGACL.
Также, для глубокого понимания темы и концепции ACL с доскональным объяснением отдельных моментов и проблем, советую почитать вот эту статью про phpGACL.
Автор пробовал Zend_Acl? Что автор думает по поводу изложенной в документации на эту тему теории, а так же о реализации?
Я ничего не думаю, я предложил свою версию для изучения.
Давайте без холи-варов, ладно?
Давайте без холи-варов, ладно?
А чего Вы нервничаете? Я всего-лишь поинтересовался Вашим мнением… Нет так нет
habrahabr.ru/blogs/webdev/51327/#comment_1357359
Zend_Acl решает немного другие задачи, нежели описанные в этой статье.
Zend_Acl решает немного другие задачи, нежели описанные в этой статье.
Извеняюсь за занудство:
Каждый раз творить темповую таблицу как то жестоко, однако
использование запросов в конструкторах не очень хорошо — такие классы очень сложно тестировать. Он сразу при инициализации полезет в базу данных, а надо бы сделать отдельный метод.
Нигде не нашел линк на коннект с базой. Вы используете последнее подключение чтоли? А если надо в две базы полезть, то будете переписывать все что связано с правами?
имхо над архитектурой надо подумать еще
Нигде не нашел линк на коннект с базой. Вы используете последнее подключение чтоли? А если надо в две базы полезть, то будете переписывать все что связано с правами?
имхо над архитектурой надо подумать еще
UFO just landed and posted this here
UFO just landed and posted this here
Zend_Acl создан для решения немного других задач.
Напомню :)
Написание собственного велосипеда — повышает квалификацию программиста :)
Написание собственного велосипеда — повышает квалификацию программиста :)
Этот метод несколько адекватнее предыдущего. Для меня — очень полезно, как раз нужно было что-то подобное, спасибо.
Или я не выспался, или реально непонятная структура БД? Например я использую, 4 таблицы:
1. Пользователи (UID)
2. Групы (GID)
3. Связка между пользователями и групами (GID->UID)
4. Таблица прав для груп и пользователей. (GID,UID — установлено первое смотрим для групы, установлено второе смотрим для пользователя)
Вот в примере «Пример, что у нас получилось», я не пойму зачем вообще вторая таблица?
1. Пользователи (UID)
2. Групы (GID)
3. Связка между пользователями и групами (GID->UID)
4. Таблица прав для груп и пользователей. (GID,UID — установлено первое смотрим для групы, установлено второе смотрим для пользователя)
Вот в примере «Пример, что у нас получилось», я не пойму зачем вообще вторая таблица?
rights_name — не нужна.
rights_group привязана к пользователям и говорит о тех правах, которыми пользователь обладает.
rights_action привязана к объектам и говорит, с каким правами, какие действия пользователь может выполнять.
rights_group привязана к пользователям и говорит о тех правах, которыми пользователь обладает.
rights_action привязана к объектам и говорит, с каким правами, какие действия пользователь может выполнять.
Насколько я понимаю, тут групами и не пахнет, только одни названия? Поскольку даже в вашем комменте нету упоминания груп, меня ввели в заблуждение rights_group и GroupID. Тогда еще один момент не понимаю, в таблице rights_action поле GroupID, если вы уже и так в таблице rights_group связали GroupID и RightsID?
Вернее групы отсутсвуют как групы пользователей, тут есть групы прав для пользователей если я правильно понял, но всеравно по связям я не понимаю =)
На пальцах:
1) `GroupID` — это integer — номер группы. У каждой группы есть своё название, соответствующее определенному числу.
2) Пользователь может быть в нескольких группах одновременно — для этого в rights_group необходимо добавить несколько ключей `groupID`. `rightsID` во всех записях должен быть равен тому Идентификатору, который будет указан у пользователя.
3) Объект так-же может иметь несколько групп `groupID` на одно действие в таблице rights_action. `rightsID` во всех записях должен соответствовать Идентификатору, который указан в данных объекта.
1) `GroupID` — это integer — номер группы. У каждой группы есть своё название, соответствующее определенному числу.
2) Пользователь может быть в нескольких группах одновременно — для этого в rights_group необходимо добавить несколько ключей `groupID`. `rightsID` во всех записях должен быть равен тому Идентификатору, который будет указан у пользователя.
3) Объект так-же может иметь несколько групп `groupID` на одно действие в таблице rights_action. `rightsID` во всех записях должен соответствовать Идентификатору, который указан в данных объекта.
А чем вам не понравились битовые маски для прав?
Хранить можно в одном поле и выбирать из базы через битовые операции.
Хранить можно в одном поле и выбирать из базы через битовые операции.
Где я такое сказал, что не понравились? :)
Битовые маски имеют свои преимушества и недостатки.
Битовые маски имеют свои преимушества и недостатки.
А в чём именно их недостатки для вашего случая?
недостаток битовой маски в том, что она ненужна при такой организации :)
и сделать ее нефиксированной длинны (т.е. хорошо расширяемой) — практически нереально.
и сделать ее нефиксированной длинны (т.е. хорошо расширяемой) — практически нереально.
Зависит полностью от проекта.
У меня здесь, хоть и рассматривается пример простейшего новосного сайта (для которого, можно использовать и битовые маски), но я не рассматриваю конкретно его, как самоцель построения такой системы. Для сайта новостей, я согласен с вами, битовая маска подойдет куда лучше, но при более серьёзной организации, начинаются проблеммы, которые решить с помошью масок сложнее.
Очень простой вариант — сайт ролевых игр, в котором используются роли (считай новые группы пользователей) и каждая из ролей имеет различные степени доступа на страницы сайта. (количество степеней доступа к странице могут привосходить 6)
Роли можно добавлять и присваивать им определенные права.
У меня здесь, хоть и рассматривается пример простейшего новосного сайта (для которого, можно использовать и битовые маски), но я не рассматриваю конкретно его, как самоцель построения такой системы. Для сайта новостей, я согласен с вами, битовая маска подойдет куда лучше, но при более серьёзной организации, начинаются проблеммы, которые решить с помошью масок сложнее.
Очень простой вариант — сайт ролевых игр, в котором используются роли (считай новые группы пользователей) и каждая из ролей имеет различные степени доступа на страницы сайта. (количество степеней доступа к странице могут привосходить 6)
Роли можно добавлять и присваивать им определенные права.
Ну вот и добавляйте разрядность, никто же вас не ограничивает, сделайте varchar(1024) и будет вам счастье.
Битовые маски хороши, но не гибки. К сожалению у них есть так же и ограничения на длинну (ну не в строку же их записывать) да и группы с ними просто так не слепишь, да и мало ли чего еще…
ACL, описаный в статье, вполне комплексное решение, вот только реализация лично меня повергла в уныние :(
ACL, описаный в статье, вполне комплексное решение, вот только реализация лично меня повергла в уныние :(
Какое ограничение на длину?
Почему не слепить группы?
Что мешает под них отдельное поле в таблице выделить, точно так же с битовой маской?
Или отдать под группу один из разрядов в существующей битовой маске.
Почему не слепить группы?
Что мешает под них отдельное поле в таблице выделить, точно так же с битовой маской?
Или отдать под группу один из разрядов в существующей битовой маске.
тоесть Вы предлагаете делать маски в строках? Допустим.
Но покажите на пальцах, как Вы реализуете систему прав с тремя ролями, которые располагаются в нескольких подгруппах для доступа к нескольким объектам, при чем доступ может быть четырех видов: операция1, операция2, операция3 и операция4.
Но покажите на пальцах, как Вы реализуете систему прав с тремя ролями, которые располагаются в нескольких подгруппах для доступа к нескольким объектам, при чем доступ может быть четырех видов: операция1, операция2, операция3 и операция4.
Ваш вопрос не очень понятен.
С точки зрения хранения, группы и операции никак не различаются.
Сделайте для групп отдельные биты и всё будет работать.
Скажем так (двоичный код):
00000001 — операция1
00000010 — операция2
00000100 — операция3
00001000 — операция4
00010000 — доступ_к_объекту_1
00100000 — доступ_к_объекту_2
01000000 — членство_в_группе_1
10000000 — членство_в_подргуппе_1_группы_1
и т.п.
Затем вам надо будет в запросе писать WHERE `code` AND `нужное_вам_условие`
Само условие можно так же формировать из битов.
С точки зрения хранения, группы и операции никак не различаются.
Сделайте для групп отдельные биты и всё будет работать.
Скажем так (двоичный код):
00000001 — операция1
00000010 — операция2
00000100 — операция3
00001000 — операция4
00010000 — доступ_к_объекту_1
00100000 — доступ_к_объекту_2
01000000 — членство_в_группе_1
10000000 — членство_в_подргуппе_1_группы_1
и т.п.
Затем вам надо будет в запросе писать WHERE `code` AND `нужное_вам_условие`
Само условие можно так же формировать из битов.
то-есть если у меня 20 групп (некоторые из них, скажем половина, находятся в подчинении друг у друга), 400 рабочих станций и по 20 возможных операций с рабочей станцией, то получается что мне можно обойтись битовыми масками. Ну тогда да — я не прав…
Ситуация, в которой ваши маски не сработают:
5 групп — администраторы, модераторы, супервизоры, пользователи, гости
Распределение:
Гости — Только читают.
Пользователи — Читают и оставляют новые сообщения.
Супервизоры — Только аппрувят новые сообщения, модерируя их.
Модераторы — Читают, оставляют и удаляют сообщения.
Администраторы — Читают, редактируют, оставляют и удаляют сообщения.
У меня 3 вопроса:
1) В вашем случае, как будет выглядеть битовая маска?
2) Как в вашем случае при разработке проекта, не теряя его целостность и не изменяя кучу кода, добавить новую группу.
3) Как в вашем случае при разработке проекта, не теряя его целостность и не изменяя кучу кода, добавить новое действие.
Если ответите на него, я приму вашу точку зрения, что битовые маски удобнее, быстрее и универсальнее. :)
5 групп — администраторы, модераторы, супервизоры, пользователи, гости
Распределение:
Гости — Только читают.
Пользователи — Читают и оставляют новые сообщения.
Супервизоры — Только аппрувят новые сообщения, модерируя их.
Модераторы — Читают, оставляют и удаляют сообщения.
Администраторы — Читают, редактируют, оставляют и удаляют сообщения.
У меня 3 вопроса:
1) В вашем случае, как будет выглядеть битовая маска?
2) Как в вашем случае при разработке проекта, не теряя его целостность и не изменяя кучу кода, добавить новую группу.
3) Как в вашем случае при разработке проекта, не теряя его целостность и не изменяя кучу кода, добавить новое действие.
Если ответите на него, я приму вашу точку зрения, что битовые маски удобнее, быстрее и универсальнее. :)
Да всё просто.
00000001-- чтение сообщений
00000010 — добавление сообщений
00000100 — апрув новых сообщений
00001000 — удалить сообщение
00010000 — редактировать сообщение
Можно ввести группы в эти права, а можно хранить их отдельно.
Сути это не изменит.
Если мы будем хранить права в отдельной табличке/в коде:
00000001 — гости
00000011 — пользователи
00000100 — супервизоры
00001011 — модератор
00011111 — администратор
Как проверять на принадлежность группе, я писал выше.
00000001-- чтение сообщений
00000010 — добавление сообщений
00000100 — апрув новых сообщений
00001000 — удалить сообщение
00010000 — редактировать сообщение
Можно ввести группы в эти права, а можно хранить их отдельно.
Сути это не изменит.
Если мы будем хранить права в отдельной табличке/в коде:
00000001 — гости
00000011 — пользователи
00000100 — супервизоры
00001011 — модератор
00011111 — администратор
Как проверять на принадлежность группе, я писал выше.
И как вы предлагаете указывать права для каждого сообщения?
Я сейчас вижу 5 байт. Каждую маску в БД записывать?
У вас это будет работать на глобальных правах.
А если локально выбирать для каждого сообщения, во сколько раз табличка увеличится?
А если групп пользователей будет больше — таблица сразу сильно увеличится.
Ваш вариант не подходит под поставленную задачу «Каждое сообщение новостей имеет свои права».
Я сейчас вижу 5 байт. Каждую маску в БД записывать?
У вас это будет работать на глобальных правах.
А если локально выбирать для каждого сообщения, во сколько раз табличка увеличится?
А если групп пользователей будет больше — таблица сразу сильно увеличится.
Ваш вариант не подходит под поставленную задачу «Каждое сообщение новостей имеет свои права».
Скажите, а вы понимаете что способ хранения прав в битовых масках и ваш способ — одинаков по сути?
Различия в том, что вы храните права в одном байте, а я предлагаю хранить в одном бите.
Вы предлагаете плодить записи в таблице, я предлагаю сохранять все права в одной записи (читай атомарность).
Способ, который я предлагаю — компактнее, только и всего.
Видимо вы, как и другие критикующие, не потрудились разобраться в том, что именно я предлагаю и говорите ерунду.
Различия в том, что вы храните права в одном байте, а я предлагаю хранить в одном бите.
Вы предлагаете плодить записи в таблице, я предлагаю сохранять все права в одной записи (читай атомарность).
Способ, который я предлагаю — компактнее, только и всего.
Видимо вы, как и другие критикующие, не потрудились разобраться в том, что именно я предлагаю и говорите ерунду.
Ваше предложение имело бы смысл, если число аттрибутов ограничивалось бы 4мя (чтение, изменение, удаление, создание). А вся остальная логика и иерархия хранилась бы отдельно. Но тут встает вопрос, а зачем нам заниматься глупостью и использовать винегрет методов и подходов, вместо одного?
Впрочем, вы нигде! о разумном ограничении не оговорились :)
Более того вы проявили себя как неуемный сторонник битовых масок везде и всюду :)
varchar(1024) в сочетании с нынешним заявлением об 1м байте особенно порадовали.
Впрочем, вы нигде! о разумном ограничении не оговорились :)
Более того вы проявили себя как неуемный сторонник битовых масок везде и всюду :)
varchar(1024) в сочетании с нынешним заявлением об 1м байте особенно порадовали.
varchar(1024) появилось как результат предложения одного из участников беседы, что есть ограничения на длину (почитайте внимательно первый пост этого треда).
Зачем вы теперь про него везде говорите, мне не понятно.
Вы троль?
Зачем вы теперь про него везде говорите, мне не понятно.
Вы троль?
Да-да, я троль, когда настроение хорошее :)
Я внимательно читал весь тред. Вы не учитываете, что собеседник может иметь точку зрения отличную от вашей. Автор топика отлично это показал habrahabr.ru/blogs/webdev/51327/#comment_1358291
И более того ваши умолчания, это только «ваши» умолчания, и для читающих они далеко не очевидны. Поэтому, если вас не затруднит, раскрывайте свою мысль полнее. А еще лучше в виде отдельной статьи о преимуществе битовых масок. Вам все будут благодарны.
Я внимательно читал весь тред. Вы не учитываете, что собеседник может иметь точку зрения отличную от вашей. Автор топика отлично это показал habrahabr.ru/blogs/webdev/51327/#comment_1358291
И более того ваши умолчания, это только «ваши» умолчания, и для читающих они далеко не очевидны. Поэтому, если вас не затруднит, раскрывайте свою мысль полнее. А еще лучше в виде отдельной статьи о преимуществе битовых масок. Вам все будут благодарны.
Я говорю про то, что в вашем случае сохранять права в одной записи не получится — потому что существует двухмерная таблица (Действие, Группа) битов.
Хорошо, храните в нескольких, никто вам не мешает.
Я и не настаивал на том что всё должно хранится в одном поле, а приводил такую ситуацию как возможный пример.
А дальше всё зависит от архитектуры.
Я и не настаивал на том что всё должно хранится в одном поле, а приводил такую ситуацию как возможный пример.
А дальше всё зависит от архитектуры.
Да, вы правы. Единственный недостаток — это плохая читаемость человеком. По производительности и занимаемому месту БД (особенно, если необходимо будет проверить несколько действий одновременно) оно будет превосходить описанный здесь метод.
Единственное, что необходимо будет придумать — это быструю реализацию битовых операций AND и NAND.
Единственное, что необходимо будет придумать — это быструю реализацию битовых операций AND и NAND.
Круто.
А теперь у нас появилась новая группа для одного объекта. Вводим новый бит?
И для корректной работы обновляем все!!! маски в базе?
А не проще ли добавить 1!!! запись для одного объекта?
А теперь у нас появилась новая группа для одного объекта. Вводим новый бит?
И для корректной работы обновляем все!!! маски в базе?
А не проще ли добавить 1!!! запись для одного объекта?
Не понял, зачем обновлять все маски?
Обновите только маски тех объектов для которых эта новая группа введена.
Обновите только маски тех объектов для которых эта новая группа введена.
Да ну?
Было — 10001
стало — 110001
А при добавлении следующей группы?
Тоже маски только у тех объектов?
Было — 11001
стало — 111001
А должно быть 1011001
Т.е. вам, как минимум, надо где-то контролировать длину маски
Было — 10001
стало — 110001
А при добавлении следующей группы?
Тоже маски только у тех объектов?
Было — 11001
стало — 111001
А должно быть 1011001
Т.е. вам, как минимум, надо где-то контролировать длину маски
Я может что-то и не понимаю. Зачем контролировать длину маски?
Вы про битовые операции читали? XOR, OR, AND?
Добавлении бита слева никак не повлияет на предыдущие проверки.
Попробуйте сами проверить, в том же калькуляторе.
Пример с «А должно быть» вообще не понял. Почему вы решили что будет так? Откуда взялся ноль?
Вы про битовые операции читали? XOR, OR, AND?
Добавлении бита слева никак не повлияет на предыдущие проверки.
Попробуйте сами проверить, в том же калькуляторе.
Пример с «А должно быть» вообще не понял. Почему вы решили что будет так? Откуда взялся ноль?
Ну смотрите.
Я добавил новую скажем группу(право/действие — не суть важно) Буки-Вуки
Теперь на принадлежность объекта к этой группе будет указывать новый бит.
И мы его обновляем у нужных нам объектов.
Было — 10001
стало — 110001 (1й объект)
Некоторое время спустя взбрело мне в голову добавить еще один критерий Вака-Вака и нужен еще один новый бит.
Если следовать вашим рекомендациям мы тупо добавляем
его к нужным нам объектам
Было — 11001
стало — 111001 (2й объект)
Вот только как мы теперь отличим за что отвечают крайние слева биты? :)
110001 (1й объект)
111001 (2й объект)
Вот для этого и нужен учет длины
Тогда мы получим
0110001 (1й объект)
1011001 (2й объект)
И да, если я вдруг (ну вот так сложилось)
захочу сделать поиск объектов по их правам/группам/действиям, да не по всем, а какому-то конкретному…
Все будет еще интереснее.
Я добавил новую скажем группу(право/действие — не суть важно) Буки-Вуки
Теперь на принадлежность объекта к этой группе будет указывать новый бит.
И мы его обновляем у нужных нам объектов.
Было — 10001
стало — 110001 (1й объект)
Некоторое время спустя взбрело мне в голову добавить еще один критерий Вака-Вака и нужен еще один новый бит.
Если следовать вашим рекомендациям мы тупо добавляем
его к нужным нам объектам
Было — 11001
стало — 111001 (2й объект)
Вот только как мы теперь отличим за что отвечают крайние слева биты? :)
110001 (1й объект)
111001 (2й объект)
Вот для этого и нужен учет длины
Тогда мы получим
0110001 (1й объект)
1011001 (2й объект)
И да, если я вдруг (ну вот так сложилось)
захочу сделать поиск объектов по их правам/группам/действиям, да не по всем, а какому-то конкретному…
Все будет еще интереснее.
Т.е. вы указываете на ситуацию что добавляя права, вы не будете знать каким битом это сделано?
Каждое право записывается своим числом. И ситуация которую вы описали не возможна.
Может вам станет понятнее если вы переведёте число из двоичного кода в десятичный код.
Поиск по объектам делается через битовые операции.
Вы попробуйте написать небольшую програму на php и посмотреть что получается. А то у меня складывается ощущение что вы критикуете то, что никогда не пробовали делать. Отсюда и такие ошибки.
Каждое право записывается своим числом. И ситуация которую вы описали не возможна.
Может вам станет понятнее если вы переведёте число из двоичного кода в десятичный код.
Поиск по объектам делается через битовые операции.
Вы попробуйте написать небольшую програму на php и посмотреть что получается. А то у меня складывается ощущение что вы критикуете то, что никогда не пробовали делать. Отсюда и такие ошибки.
Ошибки? Вы же сами предложили тупо добавить бит слева.
Вы не сказали установить бит в нужной позиции. sic!
Когда я вам сказал, что нужно контролировать длину маски (как раз чтобы знать позицию) вы жутко этому удивились :) Вы теоретик?
Как, по-вашему, происходит установка/сброс бита?
Можете ли вы сделать это не зная его позиции?
Что проще запомнить 20-30 степеней двойки или мнемонику?
(ах, да, есть отличный выход — добавлять новые константы — просто умопомрачительное решение)
Что касается поиска при помощи битовых операций :)
Спасибо насмешили. Вы не пробовали смотреть на вопрос не столь однобоко?
Как, по-вашему, поведут себя индексы с масками, учитывая ваше предложение о varchar(1024).
Те же bitmap-индексы, в которые меня пытались ткнуть :) Отлично будут работать, если у нас будет несколько полей, которые хранят 1/0. Но это противоречит вашей идее маски в одном поле :)
Вы не сказали установить бит в нужной позиции. sic!
Когда я вам сказал, что нужно контролировать длину маски (как раз чтобы знать позицию) вы жутко этому удивились :) Вы теоретик?
Как, по-вашему, происходит установка/сброс бита?
Можете ли вы сделать это не зная его позиции?
Что проще запомнить 20-30 степеней двойки или мнемонику?
(ах, да, есть отличный выход — добавлять новые константы — просто умопомрачительное решение)
Что касается поиска при помощи битовых операций :)
Спасибо насмешили. Вы не пробовали смотреть на вопрос не столь однобоко?
Как, по-вашему, поведут себя индексы с масками, учитывая ваше предложение о varchar(1024).
Те же bitmap-индексы, в которые меня пытались ткнуть :) Отлично будут работать, если у нас будет несколько полей, которые хранят 1/0. Но это противоречит вашей идее маски в одном поле :)
Из примеров что я приводил, достаточно ясно следует что позиция нужного бита мне за ранее известна.
Длину маски контролировать нет нужды. Она никак не связана с позицией нужного бита, это следует из примеров и вышесказанного.
Да, одно из ограничений битовых масок, плохая читаемость человеком.
Уже нельзя открыть базу и быстро понять по выборке какие есть права у человека.
Но, как показывает опыт, задача хранения прав решается однократно. Плюс, если сильно хочется, можно легко написать скриптик, который будет делать выборки из базы по нужным условиям.
Не столько однобоко, это как?
Индексы поведут себя замечательно.
А что за bitmap-индексы? И какой идеи они противоречат?
Длину маски контролировать нет нужды. Она никак не связана с позицией нужного бита, это следует из примеров и вышесказанного.
Да, одно из ограничений битовых масок, плохая читаемость человеком.
Уже нельзя открыть базу и быстро понять по выборке какие есть права у человека.
Но, как показывает опыт, задача хранения прав решается однократно. Плюс, если сильно хочется, можно легко написать скриптик, который будет делать выборки из базы по нужным условиям.
Не столько однобоко, это как?
Индексы поведут себя замечательно.
А что за bitmap-индексы? И какой идеи они противоречат?
Уф.
Нужного известна, а нового? А следующего нового? Вы у себя в блокнотике это запишите? Или как?
Что касается bitmap индексов — www.oracle.com/technology/pub/articles/sharma_indexes.html
Что касается частоты решения задач — Задача хранения прав решается однократно, а вот поддержка и модификация этой реализации — решается постоянно.
И ради мифических преимуществ вы хотите создать людям геморрой невероятных объемов :)
В общем, с вас статья о битовых масках :) И с примерами реализации, как у автора топика :) Меня не убедите, но для остальных… это будет полезно.
Нужного известна, а нового? А следующего нового? Вы у себя в блокнотике это запишите? Или как?
Что касается bitmap индексов — www.oracle.com/technology/pub/articles/sharma_indexes.html
Что касается частоты решения задач — Задача хранения прав решается однократно, а вот поддержка и модификация этой реализации — решается постоянно.
И ради мифических преимуществ вы хотите создать людям геморрой невероятных объемов :)
В общем, с вас статья о битовых масках :) И с примерами реализации, как у автора топика :) Меня не убедите, но для остальных… это будет полезно.
я подготовил статью по своей системе кеширования, но похоже, что у меня недостаточно кармы, такчто как наберусь сил — появится еще одна версия системы разделения прав
Как все запущено :)))
Дабы не изобретать велосипеды с «доступами», надо вначале вылизать архитектуру проекта. Начиная от контроллеров, заканчивая модулями, блоками. Контроллер вполне может отдавать (обьединять, распределять) права на обьект из модулей обьеденяя права ACL+мультиюзер и аля *nix.
Все зависит от архитектуры проекта. Приведенный топик не рассказывает об архитектуре проекта поэтому судить о «правильности» реализации не имеет смысла. Отсюда может возникнyть холивар zend acl или *nix доступ и т.п. При обычное реляционной системе, хватит и acl (zend, fw). При других архитектурах у меня большие сомнения в «правильности» топика. Пока вижу топик, как рассказы на пальцах.
Дабы не изобретать велосипеды с «доступами», надо вначале вылизать архитектуру проекта. Начиная от контроллеров, заканчивая модулями, блоками. Контроллер вполне может отдавать (обьединять, распределять) права на обьект из модулей обьеденяя права ACL+мультиюзер и аля *nix.
Все зависит от архитектуры проекта. Приведенный топик не рассказывает об архитектуре проекта поэтому судить о «правильности» реализации не имеет смысла. Отсюда может возникнyть холивар zend acl или *nix доступ и т.п. При обычное реляционной системе, хватит и acl (zend, fw). При других архитектурах у меня большие сомнения в «правильности» топика. Пока вижу топик, как рассказы на пальцах.
И еще добавлю. Представленная вами система разделения прав не совсем гибкая, на мой взгляд. Или вы не все рассказали об архитектуре.
ACL не совсем удобная система, мы использовали ее в своих приложениях, лишь по тому, что она уже встроена в cakephp, но у нее больше недостатков, нежели достоинств, среди которых:
— сложность понимания (объяснить потом что-то клиенту особенно сложно)
— юзер не может быть в нескольких группах одновременно
— при необходимости ограничения доступа отдельныи юзерам сильно раздуваются таблички (необходимо хранить id каждого юзера )
— отсутсвие кеширования (это конечно не совсем к ACL но сделать кеширование не так просто)
— необходимость делать визуализацию для работы с группами и правами, что не так уж и просто, особенно в случае, если права даются определенной группе лиц.(например, пост могут редактировать создатель, админ и друзья создателя)
— сложность понимания (объяснить потом что-то клиенту особенно сложно)
— юзер не может быть в нескольких группах одновременно
— при необходимости ограничения доступа отдельныи юзерам сильно раздуваются таблички (необходимо хранить id каждого юзера )
— отсутсвие кеширования (это конечно не совсем к ACL но сделать кеширование не так просто)
— необходимость делать визуализацию для работы с группами и правами, что не так уж и просто, особенно в случае, если права даются определенной группе лиц.(например, пост могут редактировать создатель, админ и друзья создателя)
Посмотрите библиотеку DbSimple для общения с базой данных. Она сильно упростит ваш SQL и его обработку.
И еще… пишите лучше код вот так:
'SELECT field FROM table WHERE other_field = '. $this->getID(). 'AND some_field = '. $this->getGroup()
В таком виде код куда легче читать и понимать, чем, если писать все в двойных кавычках. Ну и будет чуток быстрей работать… но это правда что-то сродни мифу, реально это добавит каплю скорости в обработку (((=
И еще мой совет — не используете запросы с объединение таблиц. Если вы делаете CMS, то это значит, что скорее всего ваша система будет ставиться на обычный хостинг, а если вы будете на популярных страницах использовать такие запросы — база будет недовольна нагрузкой (= Лучше несколько простых запросов, чем один сложный (=
'SELECT field FROM table WHERE other_field = '. $this->getID(). 'AND some_field = '. $this->getGroup()
В таком виде код куда легче читать и понимать, чем, если писать все в двойных кавычках. Ну и будет чуток быстрей работать… но это правда что-то сродни мифу, реально это добавит каплю скорости в обработку (((=
И еще мой совет — не используете запросы с объединение таблиц. Если вы делаете CMS, то это значит, что скорее всего ваша система будет ставиться на обычный хостинг, а если вы будете на популярных страницах использовать такие запросы — база будет недовольна нагрузкой (= Лучше несколько простых запросов, чем один сложный (=
по поводу того, что лучше запустить из php несколько запросов или один с JOIN я бы поспорил. При том, что если еще подумать об кешировании запросов и грамотном расставлении индексов.
Не, тут возможно вы и правы. Просто я думаю так:
Если таблицы маленькие, пользователей не так много, то несколько селектов, причем простых (по индексам), не нагрузят систему. Это просто уменьшит количество php — кода. Если вы начинаете говорить о кеширование, то это уже не такой простой проект… по крайней мере кеширование средствами MySQL практически по дефолту используется. А если нагрузка на проект большая, то тут уже могут быть проблемы. У меня в проекте, где и не такая уж большая посещаемость, но крупные таблицы, базе не хватило памяти, что выполнить JOIN… в итоге пошла запись на жесткий диск… следовательно образовалась очередь из запросов со всеми вытекающими 502-ми.
Если таблицы маленькие, пользователей не так много, то несколько селектов, причем простых (по индексам), не нагрузят систему. Это просто уменьшит количество php — кода. Если вы начинаете говорить о кеширование, то это уже не такой простой проект… по крайней мере кеширование средствами MySQL практически по дефолту используется. А если нагрузка на проект большая, то тут уже могут быть проблемы. У меня в проекте, где и не такая уж большая посещаемость, но крупные таблицы, базе не хватило памяти, что выполнить JOIN… в итоге пошла запись на жесткий диск… следовательно образовалась очередь из запросов со всеми вытекающими 502-ми.
ну это уже проблема проектирования БД. Не стоит делать широких таблиц — лучше разбить на нексколько. так таблички будут не столь большими и с ними будет проще работать. И если нехватило памяти, то это наверное какой-нибудь cross join был, может запрос был составлен не правильно и join шел не по индексному полю. Когда начинается проект то не всегда известно будет он высоко нагруженный или нет.
На мой взгляд, приятнее читать такой код:
'SELECT field FROM table WHERE other_field=? AND some_field=? ', $this->getID(), $this->getGroup()
:)
'SELECT field FROM table WHERE other_field=? AND some_field=? ', $this->getID(), $this->getGroup()
:)
Ну по этому поводу я написал, что DbSimple рулит (=
Я просто уже давно пользуюсь своим DBSimple :), который давно перерос в библиотеку SQLquery
Например, запрос на update состоит из
$tabledb->update(SQLquery(array('user'=>$username,'date'=>$date))->where('`ID`=?',$id))
либо
$tabledb->update(SQLquery('`ID`=?',$id)->set(array('user'=>$username,'date'=>$date))).
Да и что говорить, моя библиотека разрослась уже давно и переросла в объекты DBitem, в которых изменяя табличные значения $this->user, $this->date, делая $this->updateDB() — автоматически идёт сохранение необходимых изменений.
Например, запрос на update состоит из
$tabledb->update(SQLquery(array('user'=>$username,'date'=>$date))->where('`ID`=?',$id))
либо
$tabledb->update(SQLquery('`ID`=?',$id)->set(array('user'=>$username,'date'=>$date))).
Да и что говорить, моя библиотека разрослась уже давно и переросла в объекты DBitem, в которых изменяя табличные значения $this->user, $this->date, делая $this->updateDB() — автоматически идёт сохранение необходимых изменений.
На обычном хостинге (шареде) как правило есть ограничения на количество запросов к СУБД в час, соответственно лучше один составной запрос, чем несколько маленьких…
Какая то непонятная у вас нормализация… либо я чего-то не понял. И почему сразу нельзя делать нормализованную базу? :)
Да и битовые маски предпочтительней в данном случае…
Да и битовые маски предпочтительней в данном случае…
Увы, это подходит только для CMS, где можно четко разграничить пользователей и группы. А есть еще вариант, когда пользователю доступна на просмотр/редактирование только какая-то определенная запись из таблицы. То есть когда действия ограничиваются не только связкой module/controller/action, но и каким-то дополнительными ограничениями.
Например: туроператор-поставщик услуг
— туроператор может просматривать и изменять все данные где угодно
— поставщик услуг может изменять только данные своей услуги. То есть у него есть права на редактирование на manage/service/view|edit|delete, но только своих услуг
И тут начинается ж.па :)
Например: туроператор-поставщик услуг
— туроператор может просматривать и изменять все данные где угодно
— поставщик услуг может изменять только данные своей услуги. То есть у него есть права на редактирование на manage/service/view|edit|delete, но только своих услуг
И тут начинается ж.па :)
Не начинается.
Варианта решения этой проблеммы 2:
1) Сразу реализовать в коде завязку на поставщика услуг и в каждую услугу выводить ID поставщика, который имеет права редактирования.
2) Если пользоваться системой, которая предоставлена здесь, то получится:
a) Поставщики имеют права — Supplier1 (возможно эти права имеет один пользователь, а можно и несколько). Для каждого нового поставщика генерируется новое SupplierN.
б) Помимо прав группы всех объектов, в котором указанно: Operator+ED (туроператор — редактирование, удаление), каждый объект услуг имеет свои права rightsID, в котором указывается: Supplier23+ED.
Варианта решения этой проблеммы 2:
1) Сразу реализовать в коде завязку на поставщика услуг и в каждую услугу выводить ID поставщика, который имеет права редактирования.
2) Если пользоваться системой, которая предоставлена здесь, то получится:
a) Поставщики имеют права — Supplier1 (возможно эти права имеет один пользователь, а можно и несколько). Для каждого нового поставщика генерируется новое SupplierN.
б) Помимо прав группы всех объектов, в котором указанно: Operator+ED (туроператор — редактирование, удаление), каждый объект услуг имеет свои права rightsID, в котором указывается: Supplier23+ED.
Оо. У нас тут каша понажористее :) Оставлю в качестве примера поставщика, хотя речь пойдет об агентствах. Но для идеи сойдет :)
Поставщик может выделять подюзеров с разграничением прав (например, бухгалтер может только смотреть отчеты по продажам услуг, а главный директор — изменять и добавлять услуги)
То есть поставщику надо иметь доступ к manage/users с хитро ораниченными правами (на самом деле — к отдельному модулю типа user/manage/users, чтобы не превращать код в кашу)
И туроператор может иметь несколько пользователей. Например (реальные примеры).
— Главный оператор имет доступ ко всем заказам всех агентств ко всем поставщикам
— Оператор Надя имеет доступ только к заказам от агентств А, Б, В
— Оператор Вера имеет доступ только к заказам от агентств Г, Д
— главный оператор ушел в отпуск и открыл оператору Свете временный досутп к заказам от агентств А, В и Ж — но только на чтние, а не на редактирование
:)))
То есть да, оно более-менее ложится на ACL или схемы, подобные ACL. Но когда это начинаешь кодировать… И воплощать в интерфейсе… Волосы становятся дыбом :) На спине :))))
ТО есть я жопу имл в виду, скорее, с этой стороны. Потому что начинают смешиваться ACL'и конкретных модулей с ACL'ями данных в базе (то есть, грубо говоря ACL'и логики с ACL'ями данных).
Поставщик может выделять подюзеров с разграничением прав (например, бухгалтер может только смотреть отчеты по продажам услуг, а главный директор — изменять и добавлять услуги)
То есть поставщику надо иметь доступ к manage/users с хитро ораниченными правами (на самом деле — к отдельному модулю типа user/manage/users, чтобы не превращать код в кашу)
И туроператор может иметь несколько пользователей. Например (реальные примеры).
— Главный оператор имет доступ ко всем заказам всех агентств ко всем поставщикам
— Оператор Надя имеет доступ только к заказам от агентств А, Б, В
— Оператор Вера имеет доступ только к заказам от агентств Г, Д
— главный оператор ушел в отпуск и открыл оператору Свете временный досутп к заказам от агентств А, В и Ж — но только на чтние, а не на редактирование
:)))
То есть да, оно более-менее ложится на ACL или схемы, подобные ACL. Но когда это начинаешь кодировать… И воплощать в интерфейсе… Волосы становятся дыбом :) На спине :))))
ТО есть я жопу имл в виду, скорее, с этой стороны. Потому что начинают смешиваться ACL'и конкретных модулей с ACL'ями данных в базе (то есть, грубо говоря ACL'и логики с ACL'ями данных).
Ничего сложного, и тем более жопного:
— Главный оператор: OperatorALL
— Надя: User110
— Вера: User109
— И Света: User111
Теперь агенства:
— Агенство А: OperatorALL+VED, User110+VED, User111(Света, помните?)+V
— Агенство B: OperatorALL+VED, User110+VED
— Агенство C: OperatorALL+VED, User110+VED, User111+V
— Агенство D: OperatorALL+VED, User109+VED
— Агенство E: OperatorALL+VED, User109+VED
— Агенство F(Ж): OperatorALL+VED, User111+V
(что такое action Z — ниже)
Теперь с поставщиками:
На каждом объекте пользователя будет SupplierID (либо SupplierRights, если один пользователь принадлежит нескольким поставщикам, но разберем простой вариант). Каждый поставщик имеет права на их агенстве: Supplier21+Z, который может добавлять своих (у которых SupplierID совпадает с SupplierID человека с правами Supplier21 в нашем примере) подюзеров в агенство с различными правами.
В принципе всё :)
— Главный оператор: OperatorALL
— Надя: User110
— Вера: User109
— И Света: User111
Теперь агенства:
— Агенство А: OperatorALL+VED, User110+VED, User111(Света, помните?)+V
— Агенство B: OperatorALL+VED, User110+VED
— Агенство C: OperatorALL+VED, User110+VED, User111+V
— Агенство D: OperatorALL+VED, User109+VED
— Агенство E: OperatorALL+VED, User109+VED
— Агенство F(Ж): OperatorALL+VED, User111+V
(что такое action Z — ниже)
Теперь с поставщиками:
На каждом объекте пользователя будет SupplierID (либо SupplierRights, если один пользователь принадлежит нескольким поставщикам, но разберем простой вариант). Каждый поставщик имеет права на их агенстве: Supplier21+Z, который может добавлять своих (у которых SupplierID совпадает с SupplierID человека с правами Supplier21 в нашем примере) подюзеров в агенство с различными правами.
В принципе всё :)
Вы посмотрите — у меня в примере Новостной ленты — Вся лента имеет Admin+, а конкретные сообщения User1+
Ложка дегтя в бочку. К сожалению данная система подходит тока к сайтом с мизерной посещаемостью, про Зеден вообще умолчу. От join таварищи уже давно надо было избавиться. Кто то упоминал про Нормализацию так это уже прошлый век, сечас пошла оправданная мода на денормализацию, что качественно влияет на скорости. Ну а о применение данного подхода в соц. сетях. и говорить не приходится.
А вообще статья написана вполне качественно, подробно и она мне понравилась (плюсанул) но к сожалению опоздала даже в рунете лет так на 7-8.
А вообще статья написана вполне качественно, подробно и она мне понравилась (плюсанул) но к сожалению опоздала даже в рунете лет так на 7-8.
а что, это нормально если поля, несущие разную смысловую нагрузку одинаково называются?
минуты 3 врубался в нормализованную структуру пока понял что поле RightsID в таблицах rights_action и rights_group имеют разное значение
минуты 3 врубался в нормализованную структуру пока понял что поле RightsID в таблицах rights_action и rights_group имеют разное значение
Sign up to leave a comment.
Система разделения прав доступа в веб-приложении