Простое создание закрытых разделов

Перевод заметки Create Protected Pages the Easy Way

Из данной статьи вы узнаете как быстро и легко скрыть страницы для не авторизованных пользователей вашего сайта с помощью сниппета.


Контексты

Один из методов — поместить все закрытые ресурсы в отдельный контекст и защитить его, создав запись ACL доступа к контексту, дав доступ одной или нескольким группами пользователей.
Как только вы это сделаете, ресурсы в контексте будут скрыты от всех, кто не является членом указанной группы или групп.
Я стараюсь по возможности воздерживаться от использования контекстов, потому что их сложно правильно настроить и они создают некоторые сложности. Например, ссылки на ресурсы в других контекстах могут быть сложными для реализации, и пользователи часто попадают на страницу с ошибкой 404 (страница не найдена), а не на страницу с ошибкой авторизации.

Группы ресурсов

Это, вероятно, наиболее часто используемый метод. Он включает в себя размещение закрытых страниц в отдельной группе ресурсов и их защиту с помощью записи ACL, дав доступ одной или нескольким группам пользователей. Обратной стороной этого метода является то, что вы должны не забывать помещать все новые закрытые страницы в группу ресурсов, и настроить редирект пользователей на страницу с ошибкой при попытке доступа к этим страницам.

Простой способ — настраиваемый сниппет

Этот метод мне больше всего нравится в простых ситуациях, когда вы хотите защитить раздел своего сайта либо от пользователей, которые не вошли в систему, либо от пользователей, не входящих в одну или несколько групп пользователей. Это быстро и просто, а также позволяет отправлять пользователя куда угодно, когда он пытается получить доступ к запрещенной странице.

Суть этого метода — вызвать нужный сниппет в шаблоне, используемый закрытыми страницами. Сниппет проверяет статус пользователя и при необходимости перенаправляет его. Назовем его PrivatePage.

Вызываем в шаблоне:
[[!PrivatePage]]

На феноме:
{'!PrivatePage'|snippet}

Сам код сниппета:
<?php
/* PrivatePage snippet */
/* Redirect anyone who is not logged in */

$key = $modx->context->get('key');
if (! $modx->user->hasSessionContext($key)) {
   $modx->sendUnauthorizedPage();
}
return '';

Для пользователей, авторизованных в текущем контексте (обычно «web»), сниппет вообще ничего не делает. Однако пользователи, которые не вошли в систему, попадают на не авторизованную страницу (по умолчанию Главная (id=1)).
Вы можете установить идентификатор этой страницы в системной настройке unauthorized_page.
Просто перейдите в раздел «Система» (значок шестеренки) -> «Системные настройки» в главном меню, введите «unauthorized» в поле поиска в правом верхнем углу и нажмите клавишу Enter. Найдите параметр unauthorized_page и дважды щелкните поле значения. Измените идентификатор страницы, на которую хотите отправить пользователя. Например, это может быть страница входа в систему.

Предположим, вы хотите ограничить доступ к закрытым страницам членам определенной группы пользователей.
Версия сниппета, представленная ниже поможет в этом. Просто измените SomeUserGroup на название вашей группы пользователей.
<?php
/* PrivatePage snippet */
/* Redirect anyone who is not a
 * member of a particular user group */

if (! $modx->user->isMember('SomeUserGroup')) {
$modx->sendUnauthorizedPage();
}
return '';

Если же необходимо, чтобы доступ к закрытому разделу был у пользователей из нескольких групп, то необходимо внести небольшие изменения в сниппет:
if (! $modx->user->isMember( array( 'SomeUserGroup', 'SomeOtherUserGroup'))) {

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

Отправить их куда-нибудь еще

Возможно, вы уже используете неавторизованную страницу для чего-то еще или, может быть, вам просто хочется отправить пользователей на какую-то другую страницу (например, страницу входа в систему). Сделать это достаточно просто.
Просто измените вызов sendUnauthorized () на это (измените 12 на id страницы, на которую вы хотите их отправить):

$url = $modx->makeUrl(12, "", "", "full");
$modx->sendRedirect($url);

Собираем все вместе

Наш сниппет не очень гибкий. Действия, которые он выполняет, имена групп и страница, на которую выполняется перенаправление, жестко запрограммированы в сниппете. Было бы неплохо, если бы это можно было настроить в в параметрах сниппета, чтобы вы могли использовать его по-разному на разных сайтах или разных страницах (сниппет может вызываться в содержимом страницы, а не только в шаблоне). Вот более общая версия:

<?php
/* PrivatePage snippet */
/* Redirect users who shouldn't see this page */

/** @param $redirectTo string -- (optional) ID of page to redirect to;
 *      default: unauthorized page
 *  @param $userGroups string -- (optional) Comma-separated list of
 *      User Groups that are authorized;
 *      if not set, users who are not logged in are redirected
 * */

$output = '';

function forward($id, &$modx) {

    if (empty($id)) {
        $modx->sendUnauthorizedPage();
    }
    $url = $modx->makeUrl((integer) $id, "", "", "full");
    if (empty($url)) {
        die('MakeUrl failed. ID: ' . $id);
    }
    $modx->sendRedirect($url);
}

$redirectTo = $modx->getOption( 'redirectTo', $scriptProperties, '');
$userGroups = $modx->getOption( 'userGroups', $scriptProperties, '');

if ((!empty($userGroups)) && strpos( $userGroups, ',') !== false) {
    $userGroups = explode( ',', $userGroups);
}

if (empty($userGroups)) {
    /* Redirect anyone who is not logged in */
    $key = $modx->context->get('key');
    if (!$modx->user->hasSessionContext($key)) {
        forward($redirectTo, $modx);
    }
} else {
    /* redirect if not a member of specified group(s) */
    if (!$modx->user->isMember($userGroups)) {
        forward($redirectTo, $modx);
    }
}

return $output;

В этой версии есть два параметра и они оба не обязательны.
Если свойства не отправлены, пользователи, которые не вошли в систему, будут отправлены на неавторизованную страницу.
Параметр userGroups может содержать одно имя группы пользователей или список групп пользователей, разделенных запятыми. Пользователи, не являющиеся участниками, будут перенаправлены.
Если свойство redirectTo не задано, они перейдут на неавторизованную страницу. Если он установлен, они перейдут к идентификатору, указанному тут.

Примеры

Все версии сниппета перенаправляют пользователя, который не авторизован:
/* Редирект любого, не авторизованного пользователя на специальную страницу*/
[[!PrivatePage]]

{'!PrivatePage'|snippet}

/* Редирект любого, не авторизованного пользователя на ресурс с id = 12 */
[[!PrivatePage? &redirectTo=`12`]]

{'!PrivatePage'|snippet:[ 
    "redirectTo" => 12 
]}

/* Редирект любого пользователя, не входящего в группу Subscribers  на специальную страницу */
[[!PrivatePage? &userGroups=`Subscribers`]]

{'!PrivatePage'|snippet:[ 
    "userGroups" => "Subscribers" 
]}

/* Редирект любого пользователя, не входящего в группу Subscribers или Administrator  на ресурс с id = 12*/
[[!PrivatePage? &userGroups=`Subscribers,Administrator` &redirectTo=`12`]]

{'!PrivatePage'|snippet:[ 
    "userGroups" => "Subscribers,Administrator", 
    "redirectTo" => 12 
]}

Важно: убедитесь, что неавторизованная (unauthorized_page) страница (или любая другая страница, на которую вы переадресовываете) опубликована, и убедитесь, что сниппет PrivatePage не будет выполняться на этой странице!

Позволил себе привести примеры и на fenom
Евгений Webinmd
09 декабря 2021, 15:43
modx.pro
1
702
+8

Комментарии: 1

Илья Уткин
11 декабря 2021, 08:29
+2
Это все, конечно красиво и на первый взгляд просто. До тех пор, пока не появится необходимость скрывать запрещённые страницы из вывода pdoResources или pdoMenu. Тогда начинаются всякие странные выборки, условия и прочее.
    Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
    1