Проверка прав
Чтобы предотвратить изменение настроек плагина или запретить просматривать данные, доступа к которым у пользователя нет, нужно проверять права пользователя, совершать какое-либо действие.
В WordPress для этого есть два подхода:
- проверка возможностей (прав) пользователя.
- одноразовые числа (nonce).
Это разные подходы и одноразовые числа, как правило дополняют проверку прав.
В этом разделе поговорим про первый: «Проверка прав юзера».
Возможности пользователя (проверка прав)
Проверка прав - это основной и пожалуй фундаментальный момент в защите и безопасности плагина. Он проверяет возможность пользователя делать что-либо. У каждого пользователя есть роль (Подписчик, Автор, Редактор) и у каждой роли есть набор прав. С помощью функции current_user_can() мы можем проверить имеет ли текущий пользователь указанное право, например, manage_options
(право администратора изменять опции сайта). Если пользователь таким правом обладает, то функция вернет true и условие для выполнения какого-то кода будет выполнено и наоборот - если права нет, код выполняться не будет.
Например, «Автор» может публиковать и редактировать записи, но не имеет права редактировать чужие записи. А «Редактор» может публиковать и изменять свои и чужие записи. Но ни один из них не может изменять настройки сайта, как это может делать «Администратор». В зависимости от возможностей каждой роли, админ-панель WordPress будет выглядеть по-разному: например, у «Автора» будут одно меню, а у «Администратора» оно будет другое - значительно расширенно.
Список всех прав в зависимости от роли пользователя вы найдете в описании функции current_user_can().
Проверка прав пользователя на примере
При создании плагина, нужно уделять пристальное внимание ролям, которым должны быть разрешены выполнения определенных действий.
Например, давайте посмотрим на небезопасный код без проверки прав и что нехорошего в результате может получиться. Пример ниже показывает функцию, которая по задумке должна давать возможность «Редактору» удалять записи на фронтенде сайта:
## функция выводит ссылку на удаление текущей записи function frontend_delete_link(){ $url = add_query_arg( array( 'action'=> 'frontend_delete_link', 'post'=> get_the_ID() ), home_url(), ); echo "<a href='{$url}'>Удалить</a>"; }
Теперь представим, мы использовали эту функцию и вывели ссылку где-то во фронте. При клике на нее будет срабатывать следующий код обработки запроса удаления записи:
## Функция удаляет указанную в $_REQUEST['post'] запись function frontend_delete_post(){ // определим ID записи $post_id = ( isset( $_REQUEST['post'] ) ? get_post( (int) $_REQUEST['post'] ) : false; // Нет записи - выходим... if( empty($post_id) ) return; // Удаляем запись wp_trash_post( $post_id ); // Перенаправляем на страницу админки $redirect = admin_url('edit.php'); wp_safe_redirect( $redirect ); exit; } // включаем обработчик if( isset($_REQUEST['action']) && $_REQUEST['action']=='frontend_delete_link' ) { add_action('init', 'frontend_delete_post'); }
Код выше позволяет любому посетителю сайта, нажать на ссылку "Удалить" и удалить пост. А нужно, чтобы такую возможность имели юзеры с ролью «Редактор» или более старшей ролью, например, «Администратор». Если любой сможет это сделать, то вы в конечном итоге останетесь без контента.
Для этого давайте изменим код ссылки и не будет выводить ссылку для ролей младше редактора:
function frontend_delete_link(){ // выходим если нет права 'edit_others_posts', которое есть у Редакторов и более старших ролей. if( ! current_user_can( 'edit_others_posts' ) ) return; $url = add_query_arg( array( 'action'=> 'frontend_delete_link', 'post'=> get_the_ID() ), home_url(), ); echo "<a href='{$url}'>Удалить</a>"; }
Также такую проверку нужно добавить при выполнении самой операции удаления:
## Функция удаляет указанную в $_REQUEST['post'] запись function frontend_delete_post(){ // определим ID записи $post_id = ( isset( $_REQUEST['post'] ) ? get_post( (int) $_REQUEST['post'] ) : false; // Нет записи - выходим... if( empty($post_id) ) return; // выходим если нет права 'edit_others_posts', которое есть у Редакторов и более старших ролей. if( ! current_user_can( 'edit_others_posts' ) ) return; // Удаляем запись wp_trash_post( $post_id ); // Перенаправляем на страницу админки $redirect = admin_url('edit.php'); wp_safe_redirect( $redirect ); exit; } // включаем обработчик if( isset($_REQUEST['action']) && $_REQUEST['action']=='frontend_delete_link' ) { add_action('init', 'frontend_delete_post'); }
В обоих случаях, мы подтверждаем, что у текущего пользователя есть возможность edit_others_posts
, которая может быть только у «Редакторов» или ролей старше. Если такой возможности нет, мы ничего не делаем.
Логика проверки прав довольно проса и понятна. Вариантов где это нужно - очень много. И почти всегда используется функция current_user_can().
Одноразовые числа
Проверка прав - это первый и основной уровень защиты. Он разрешает или запрещает текущему пользователю заходить на страницы, видеть части контента и выполнять какие-либо действия. Но такая защита не идеальна... Почему? Читайте в разделе «Одноразовые числа».