Как структурировать группы на сайте? (администратор, полномочия администратора, личность пользователя)
Я собираюсь создать небольшую пользовательскую систему, но у меня есть вопросы.
Если бы мне нужно было создать таблицу регистрации (mysql), что плохого в том, чтобы просто хранить пароль и имя пользователя в базе данных без шифрования?
Я пытаюсь придумать, как создать административную часть. Должен ли я просто проверить столбец в базе данных, чтобы увидеть, является ли пользователь администратором или нет? Если это правда, то страница администратора будет показана.
Для полномочий администратора, скажем, у меня есть 3 полномочия: удалить пользователя, утвердить пользователя и переместить пользователя. В некоторых сценариях я могу захотеть дать некоторым людям только возможность одобрить, или удалить, или все, или любую комбинацию. Как бы я это сделал? Я думал о наличии столбца для каждой степени и чтобы скрипт проверял каждый столбец. Давайте предположим, что у меня есть более 20 сил, которые будут добавлены.
Если у меня есть веб-сайт, на котором люди могут создавать группы и становиться администраторами своих групп, и эти администраторы могут предоставлять различные комбинации полномочий администратора людям в их группе (например, Зак создает группу под названием Mountain и предоставляет одному члену возможность утверждать новые члены группы и дает второму члену возможность удалять участников и назначает третьему члену возможность удалять и утверждать. Как я буду структурировать это в MySQL? Должен ли я использовать столбцы, в которых указано, какая группа является их администратором и какие возможности они выполняют? есть? Например, столбцы: Удалить, Одобрить, GroupMemberOf, GroupAdminOf и использовать проверки.
У меня есть идея, но я хочу изучить более сложные способы.
Спасибо за ответы, однако, я действительно ищу идеи о структуре (вопрос 2 - 4). Пожалуйста, дайте мне знать, если я могу помочь прояснить вопрос.
8 ответов
- Хэшируйте пароли пользователей с уникальными солями для каждого пользователя, чтобы, когда посторонний пользователь мог получить доступ к вашей базе данных, он не мог расшифровать пароли, а соль смягчала атаки радужных таблиц.
2 - 4. Используйте таблицу для уровней доступа (1: участник, 2: модератор (утверждение), 3: администратор) и используйте еще одну другую таблицу для разрешений пользователей, где вы храните соединения "многие ко многим", например:
id (auto_increment)|usr_id|role_id|group_id
-------------------------------------------
1 |1 |3 |-1
2 |2 |2 |1
3 |2 |3 |2
4 |3 |1 |2
В вашем случае, пользователь 1 является администратором для всего сайта, пользователь 2 является администратором для группы 3 и модератором для группы 2, пользователь 3 является членом группы 2.
[РЕДАКТИРОВАТЬ:]
Еще несколько соображений по поводу ограничения полномочий для различных ролей: в зависимости от вашей настройки вы должны использовать некоторое усиление ролей для каждой страницы, например, в рамках MVC, я бы расширил базовый контроллер, чтобы потребовать (роль) функцию авторизации, которая имеет вызываться для каждого метода, в противном случае он должен вызвать исключение. Методы (страницы), не требующие входа пользователя, могут использовать фиктивную авторизацию.
Таким образом, класс авторизации будет выглядеть
class Authorization
{
public $authorized = false;
public function dummy()
{
$this->authorized = true;
}
public function member($usr_id, $group_id = null)
{
$sql = "SELECT usr_id FROM usr_roles WHERE usr_id = " . $usr_id . ($group_id !== null) ? " AND group_id " . $group_id : "";
// count the results of $sql query
// or some more stuff
if ($results > 1)
{
$this->authorized = true;
}
else
{
$this->authorized = false;
}
}
// the other functions
}
Ваш новый базовый класс контроллера будет выглядеть так:
class BaseController extends Controller
{
protected $authorization;
public function __construct()
{
$this->authorization = new Authorization();
}
public function render()
{
if ($this->authorization->authorized === true)
{
parent::render
}
else
{
// redirect to not authorized page
}
}
}
И, наконец, в итоге ваши контроллеры будут выглядеть так:
class IndexController extends BaseController
{
// some stuff, methods etc.
// methods needs logged in user and user must be a member.
public function index()
{
$this->authorization->member($session_user->getId());
}
}
[EDIT2:]
Если вы не знакомы с ООП, то вы можете сделать следующее:
Вот пример макета для таблицы ролей:
role_id|role_name
-----------------
1 |member
2 |moderator
3 |admin
Затем вы можете сделать функцию authorize() включенной во все ваши файлы:
// role_name = "member", "moderator", "admin"
function authorize($usr_id = null, $role_name = null, group_id = null)
{
// test for user in group and role, return boolean
}
В ваших файлах включите эту функцию и сделайте следующее
if (authorize($usr_id, "moderator", 2)
{
// show stuff, if user with $usr_id is moderator for group 2
}
else
{
// do something else
}
// stuff for all
- Если вы храните пароли без шифрования, вы будете раскрывать все пароли ваших клиентов, когда кому-то удастся украсть вашу базу данных или получить к ней доступ для чтения. К сожалению, большинство людей повторно используют имена пользователей и пароли между сайтами, поэтому вы наносите большой вред своим пользователям, не защищая их пароли. (Может быть, они должны знать лучше, но большинство не знают.)
1) Хранение паролей в виде открытого текста означает, что если кто-то получит доступ к вашей базе данных, он все равно не будет знать пароль. Шумиха вокруг паролей за соль и шифрование довольно глупа, простой способ подойдет любому.
$password = "Mypassword";
$salt = "a unique and constant string";
$password = md5($password.$salt);
Что это делает, это шифрует пароль через md5();
, Вы не можете вернуть пароль после того, как зашифруете его с помощью md5(). Соление также гарантирует, что просто невозможно найти пароль.
Если вы хотите сравнить и посмотреть, работает ли пароль, просто введите md5 так же, как показано ниже:
$password = "check_this_password";
if(md5($password.$salt) === $originalPassword)
{
//same password
}
2) Этот вопрос зависит от того, как вы хотите объединить группы с административной стороны вещей. Если нет других настроек разрешений, можно просто сохранить одно поле в базе данных с уровнем учетной записи. В противном случае, используйте мой следующий пункт, чтобы узнать, являются ли они администратором или нет.
3) Самый простой способ реализации системы разрешений такой: есть другие способы, но лучше не усложнять их. Если вам нужны разрешения для каждой группы, вы можете добавить дополнительный столбец, например prm_group_id
и узнать каждого пользователя в разрешении определенной группы. Но в любом случае вот как это работает:
Создать таблицу для хранения разрешений
prm_user_id | prm_permission
0 | Admin
0 | Delete
1 | Add
Каждая строка содержит флаг или разрешение. Тогда довольно просто выяснить, имеют ли они необходимое разрешение через немного SQL и PHP.
function hasPermission($permission, $userID)
{
$permissions = array();
$sql = "SELECT prm_permission FROM user_permissions WHERE prm_user_id = $userID";
$query = mysql_query($sql);
while($data = mysql_fetch_array($query))
{
$permissions[] = $data['prm_permission'];
}
//Check if they have a permission with this:
if(in_array($permission, $permissions))
{
return true;
}
return false;
}
Это позволяет вам легко добавлять и удалять разрешения, а также проверять, есть ли у них разрешение. Единственным недостатком является то, что управление разрешениями может стать хитрым.
По пунктам 2-4 вы можете обратиться к контролю доступа на основе ролей.
Я немного опоздал с игрой для этого, но вы могли бы взглянуть на то, как CakePHP делает свою авторизацию. (Если вы используете PHP, вы можете обнаружить, что использование инфраструктуры CakePHP дает вам часть этого элемента управления без необходимости его кодирования.)
пользовательские разрешения, и-CakePHP
Кроме того, я считаю полезным хранить список действий (например, CRUD или Admin) для сущностей, чтобы вы, кроме обычной таблицы "пользователь / пароль", имели бы таблицу с полями, как показано ниже.
PermID | Запретить или разрешить | Действие | сущность
Затем у вас есть другая таблица, которая отображает группы в PermId, а другая таблица, которая отображает пользователей и группы (рекурсивно, если необходимо) в группы (о чем люди уже говорили).
Запретить или разрешить означает, что вы можете создавать списки ACL, чтобы разрешить использование, или DACL, чтобы запретить использование, если по умолчанию разрешено действие (что, как правило, не самая лучшая идея), или если существует меньшая группа, которую нужно отказать. доступ внутри большего. Обычно вы сначала проверяете наличие явного Запрета на действие против сущности для группы / пользователя.
Так что у вас может быть что-то вроде:
PermID | Тип | Действие | сущность -------+-------+---------+------------ 1 | Разрешить | Читать | User_Entry 2 | Разрешить | Удалить | User_Entry 3 | Разрешить | Переместить | User_Entry 4 | Разрешить | Одобрить | User_Entry 5 | Разрешить | Создать | User_Entry
Таким образом, в качестве иллюстрации, группа администраторов может отображаться на записи 1-5, а группа "обычный пользователь" может отображаться только на 1 и 5. (Для группы читайте "персона" или "пользователь", если хотите).
Id | Grp | PermId --- + -------- + ----- 1 | Admin | 1 2 | Admin | 2 3 | Admin | 3 4 | Admin | 4 5 | Admin | 5 6 | Нормальный | 1 7 | Нормальный | 5
Очевидно, что это легко расширяется, поскольку, когда в системе возникает новое действие или сущность (например, каталог), это просто случай добавления соответствующих записей в таблицы без необходимости изменения схемы. Например, вы можете использовать действия "Все" и использовать DACL для конкретного исключения. Вот опытный пользователь, который может сделать все, кроме удаления User_Entry.
PermID | Тип | Действие | сущность -------+-------+---------+------------ 6 | Разрешить | Все | User_Entry 7 | Запретить | Удалить | User_Entry Id | Grp | PermId --- + -------- + ----- 8 | Мощность | 6 9 | Мощность | 7
В вашем случае я представляю, что сущности могут включать имя группы или какой-то токен, который будет означать "ваша домашняя группа" или что-то, например, {homegrp}/UserEntry, а не просто UserEntry, который может иметь системный администратор.
Извините, если это было немного странно, но я надеюсь, вы поняли суть этого. (Извиняюсь, если какой-либо предыдущий ответ говорил об этом, поскольку я не думаю, что прочитал полностью до конца...)
1 - Я бы посоветовал вам зашифровать свои пароли, используя уникальную соль для каждого пользователя. Таким образом, если ваша система будет взломана, пароли ваших пользователей не будут доступны хакерам (без дополнительных взломов с их стороны)
http://phpsec.org/articles/2005/password-hashing.html (немного староват, но содержит полезную информацию)
2, 3, 4 - Все это возможно с широким спектром веб-языков. Я бы посоветовал сначала ознакомиться с дизайном базы данных и выяснить, какой тип нормализации и схемы таблиц будет идеальным для вашей ситуации. Если в будущем вы решите добавить больше полномочий пользователям с правами администратора, вы можете разработать это с самого начала и избежать головной боли в будущем и при этом соответствовать вашим текущим требованиям.
http://dev.mysql.com/tech-resources/articles/intro-to-normalization.html http://www.peachpit.com/articles/article.aspx?p=30885
- Очевидно, что рекомендуется хранить его в хэше, но есть преимущества и в том, чтобы этого не делать. Это действительно сводится к тому, что вам нужно.
2+. Я собрал небольшую схему sql для этого здесь
В основном, храните пользователей, группы и необходимые вам права доступа в отдельных таблицах. Затем свяжите пользователей с группами и предоставьте разрешения пользователям в группах. Чтобы дать человеку "все", вы просто должны убедиться, что ваша логика программирования (хранимая процедура PHP или MySQL) дает новому пользователю все доступные разрешения в таблице разрешений. Чтобы сделать это в MySQL, вы можете выполнить такой запрос:
INSERT INTO group_user_permissions
SELECT `group_user`.`groupid`, `group_user`.`userid`, `permission`.`permbit`
FROM permission, `group_user`
WHERE `group_user`.`groupid` = 1
AND `group_user`.`userid` = 1
Это вставит все возможные разрешения в таблицу group_user_permission для заданных groupid и userid (в данном случае groupid 1 и userid 1).
Теперь, когда вам нужно проверить разрешения, вы можете выполнить очень простой запрос к таблице group_user_permission, чтобы проверить, есть ли у этого пользователя в этой группе разрешение делать то, что он пытается сделать. Это в конечном итоге гибко, потому что вам не придется изменять таблицы, если вам нужно переименовать разрешения, добавить разрешения или удалить разрешения.
Кроме того, из-за использования строковых ключей в таблице разрешений вы можете использовать эти значения в текстовом формате, который будет иметь смысл при их чтении (вместо использования автоинкрементных чисел). Чтобы ваши проверки PHP выглядели так:
if( $permbit === "approve" )
против
if( $permbit === 1 )
Удачи!
2.. да
3.. Это просто, если у вас есть ограниченное количество разрешений
4.. Я написал это пару лет назад, и он широко используется в большой компании. Свяжитесь со мной, если вы хотите больше информации о схеме.