Отключение или перенаправление WP-login.php
Есть ли способ предотвратить доступ посетителей (авторизованных или нет) к странице mysite.com/wp-login.php
?
У меня есть отдельная форма входа, которая полностью удовлетворяет нашим потребностям. Я знаю, что можно перестилизовать форму, генерируемую wp-login
, но я бы предпочел вообще не иметь с ней дела. Я пробовал различные фильтры и хуки, но не смог добиться перенаправления. Также я пытался использовать перенаправление через .htaccess
, и хотя это работает, это ломает функциональность моей кастомной формы входа/выхода.
Какие есть идеи?

После изучения этого вопроса и тестирования нескольких ответов, ниже представлена "очищенная" версия кода, который я использую в рабочей среде.
Эта версия не вызывает никаких уведомлений/ошибок и также позволяет работать сбросу пароля:
// Подключаем соответствующий экшен WordPress
add_action('init', 'prevent_wp_login');
function prevent_wp_login() {
// WP отслеживает текущую страницу - глобализируем переменную для доступа
global $pagenow;
// Проверяем, установлен ли $_GET['action'], и если да, загружаем в переменную $action
$action = (isset($_GET['action'])) ? $_GET['action'] : '';
// Проверяем, находимся ли мы на странице входа, и убеждаемся, что действие не 'logout'
if( $pagenow == 'wp-login.php' && ( ! $action || ( $action && ! in_array($action, array('logout', 'lostpassword', 'rp', 'resetpass'))))) {
// Загружаем URL главной страницы
$page = get_bloginfo('url');
// Перенаправляем на главную страницу
wp_redirect($page);
// Останавливаем выполнение, чтобы предотвратить загрузку страницы по любой причине
exit();
}
}

Похоже, это предотвращает доступ к WP-Login (хорошо), но окончательный exit(), кажется, полностью блокирует выполнение login(), что не соответствует нашим целям. Мы хотим, чтобы пользователи могли входить в систему, просто никогда не видя экран WP-Login. Если они введут неправильный пароль, должно происходить перенаправление на нашу пользовательскую страницу входа.

Отредактировал, и теперь это работает: нужно проверять, заполнен ли $action, перед выполнением in_array().

@Mike - Ты уверен, что твой хук срабатывает/работает? Что будет, если добавить echo "HERE";
внутри функции? Выводится ли это сообщение?

@cale_b Да, хук работает нормально. Проблема в том, что $_GET['action']
у меня пустой. Форма отправляется на /wp-login.php
(без GET-переменных в URL) и, судя по исходному коду, там даже нет поля с именем action
, поэтому даже $_REQUEST['action']
остается пустым.

@cale_b Похоже, что приведенный выше код выполняется после того, как вход уже произошел. Если я добавлю exit;
(перед wp_redirect
) и обновлю страницу, я не получаю предупреждения о повторной отправке POST-переменных на сервер, что означает, что сервер уже выполнил перенаправление. И если я обновлю страницу после этого, я оказываюсь авторизованным.

@Mike - два момента: 1) это не предназначено для предотвращения входа, а для ограничения доступа к wp-login.php (стандартной странице входа WordPress), и 2) я отредактировал ответ и немного изменил логику, что должно решить описанную вами выше проблему.

Я новичок в php и WordPress. Мой вопрос: куда в вашем коде мне нужно вставить ссылку на мою собственную страницу входа/профиля?

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

у меня работает, но есть проблемы с выходом из системы, и я не могу понять, почему

Да, это блокирует мою пользовательскую форму входа. Но если бы был способ надежно проверить переменную запроса или, возможно, реферер? Другими словами: это может быть отправной точкой. Кто-нибудь еще? Заранее спасибо ---JC

Ах да, wp-login действительно обрабатывает выход из системы. Лол. Это логично. Возможно, этого кода с плагином будет достаточно. Давай посмотрим, что ещё можно использовать, потому что я ненавижу использовать wp-login.

Я думаю, всё, что нужно — это мониторить переменные запроса при загрузке wp-login. Просто у меня сейчас нет машины, которая может это сделать.

Я использую плагин Buddypress, который перенаправляет с wp-login на кастомную страницу входа. Возможно, тебе стоит посмотреть код, чтобы понять, как это реализовано. Плагин называется Branded Login for Buddypress, разработан Brajesh Singh на (buddydev.com)

Добавьте GET-переменную для действия выхода из системы, и все будет работать нормально.
add_action('init','custom_login');
function custom_login(){
global $pagenow;
if( 'wp-login.php' == $pagenow && $_GET['action']!="logout") {
wp_redirect('http://ВАШСАЙТ.com/');
exit();
}
}

Я уже довольно долго использую WordPress-плагин Rename wp-login.php.
Он позволяет изменить путь wp-login.php
на любой другой. У меня были проблемы с ботами, атакующими страницу входа, а теперь таких запросов вообще нет.

WP-login управляет входом, выходом, регистрацией, сбросом и восстановлением пароля. Предположим, вы хотите изменить страницу входа на фронтенде. Вы можете безопасно использовать следующий код:
function custom_login_page() {
$new_login_page_url = home_url( '/login/' ); // новая страница входа
global $pagenow;
if( $pagenow == "wp-login.php" && $_SERVER['REQUEST_METHOD'] == 'GET') {
wp_redirect($new_login_page_url);
exit;
}
}
if(!is_user_logged_in()){
add_action('init','custom_login_page');
}
Этот фрагмент кода будет:
- Перенаправлять всех посетителей сайта на новую страницу входа.
- Выход из системы будет работать без проблем
- На вашей кастомной странице входа вам нужно будет создать собственные формы входа, регистрации и сброса пароля. Однако ваши кастомные формы могут безопасно отправлять данные в wp-login.php, так как POST-запросы не перенаправляются.

home_url()
уже добавляет ведущий слеш, так что в этом нет необходимости. Также $pagenow
— это (а) глобальная переменная, которая присутствует только в админке (и, возможно, на странице входа) и (б) её следует заменить на проверки свойств get_current_screen()
.

// https://codex.wordpress.org/Plugin_API/Filter_Reference/login_url#Examples
add_filter('login_url', 'custom_login_url', 10, 3);
/**
* Изменяет стандартный URL страницы входа в WordPress
*
* @param string $login_url Исходный URL входа
* @param string $redirect URL для перенаправления после входа
* @param bool $force_reauth Нужна ли принудительная повторная аутентификация
* @return string Новый URL страницы входа
*/
function custom_login_url($login_url, $redirect, $force_reauth) {
return home_url('/login/?redirect_to=' . $redirect);
}
Этот код перенаправляет пользователей на страницу /login вместо стандартной формы wp-login.

Если ваша цель — защитить wp-login.php
от посторонних, чтобы они даже не могли увидеть эту страницу, самый простой и эффективный способ — потребовать авторизацию (basic auth) для доступа к wp-login.php
.
В Apache аутентификация реализуется с помощью комбинации htaccess и файла с паролями. При первой попытке доступа к wp-login.php
в рамках сессии браузера пользователю будет предложено ввести логин и пароль (до появления формы входа WordPress).
Для упрощения можно использовать один и тот же логин и пароль для всех, кому вы хотите предоставить доступ к wp-login.php
, поскольку после успешного прохождения первого диалога аутентификации им всё равно потребуется ввести свои учетные данные WordPress.

Интересно. Полагаю, 'prompt' — это модальное окно браузера для ввода учетных данных. Думаю, это может вызвать путаницу. В идеале я хочу, чтобы этот URL не делал ничего... или, возможно, просто перенаправлял на главную страницу. Но спасибо за информацию. Каждый день узнаю что-то новое!

То, что вы делаете, называется "безопасность через скрытность". Но на самом деле вы просто скрываете, и это ужасная практика. Не используйте её. Аутентификация — это безопасность. Скрытие точки входа — это просто скрытность. http://security.stackexchange.com/questions/32064/at-what-point-does-something-count-as-security-through-obscurity

Другими словами, даже если вы измените расположение wp-login, вам всё равно нужно использовать аутентификацию: "Стоит ли полагаться на смену порта сервера с 22 на 2222 для обеспечения безопасности соединения? Абсолютно нет. Плохо ли изменить порт SSH-сервера на 2222, продолжая использовать пароль? Нет, это даже лучшее решение. Изменение ("скрытие") порта просто уменьшит количество автоматических сканеров, ищущих уязвимости на стандартных портах. Мы получаем преимущество в безопасности за счёт скрытности, что хорошо, но мы не полагаемся только на скрытность. Если злоумышленник найдёт порт, ему всё равно нужно будет взломать пароль."

Замените $pageid
на страницу, на которую вы хотите перенаправлять пользователей
/* Перенаправление страницы входа */
function redirect_login_page(){
// Сохраняем для проверки, равна ли эта страница wp-login.php
$page_viewed = basename( $_SERVER['REQUEST_URI'] );
// Постоянная ссылка на кастомную страницу входа
$login_page = get_permalink($pageid);
if( $page_viewed == "wp-login.php" ) {
wp_redirect( $login_page );
exit();
}
}
add_action( 'init','redirect_login_page' );

<?php
/* Шаблон: Регистрация */
if(is_user_logged_in()) { $user_id = get_current_user_id();$current_user = wp_get_current_user();$profile_url = get_author_posts_url($user_id);$edit_profile_url = get_edit_profile_url($user_id); ?>
<div class="regted">
Вы вошли как <a href="<?php echo $profile_url ?>"><?php echo $current_user->display_name; ?></a> Хотите <a href="<?php echo esc_url(wp_logout_url($current_url)); ?>">выйти</a> ?
</div>
<?php } else { ?>
<div class="register">
<?php $err = ''; $success = ''; global $wpdb, $PasswordHash, $current_user, $user_ID; if(isset($_POST['task']) && $_POST['task'] == 'register' ) { $pwd1 = $wpdb->escape(trim($_POST['pwd1']));
$pwd2 = $wpdb->escape(trim($_POST['pwd2']));
$email = $wpdb->escape(trim($_POST['email']));
$username = $wpdb->escape(trim($_POST['username']));
if( $email == "" || $pwd1 == "" || $pwd2 == "" || $username == "") {
$err = 'Пожалуйста, заполните все поля';
} else if(!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$err = 'Некорректный email';
} else if(email_exists($email) ) {
$err = 'Email уже существует';
} else if($pwd1 <> $pwd2 ){
$err = 'Пароли не совпадают';
} else {
$user_id = wp_insert_user( array ('user_pass' => apply_filters('pre_user_user_pass', $pwd1), 'user_login' => apply_filters('pre_user_user_login', $username), 'user_email' => apply_filters('pre_user_user_email', $email), 'role' => 'subscriber' ) );
if( is_wp_error($user_id) ) {
$err = 'Ошибка при создании пользователя.';
} else {
do_action('user_register', $user_id);
$success = 'Регистрация прошла успешно';
}
}
}
?>
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<!--сообщения об ошибках/успехе-->
<div id="message">
<?php
if(! empty($err) ) :
echo ''.$err.'';
endif;
?>
<?php
if(! empty($success) ) :
$login_page = home_url( '/login' );
echo ''.$success. '<a href='.$login_page.'> Войти</a>'.'';
endif;
?>
</div>
<div class="container">
<div id="loginbox" style="margin-top:100px;" class="mainbox col-md-6 col-md-offset-3 col-sm-8 col-sm-offset-2">
<div style="padding-bottom: 50px;" class="col-md-6 col-md-offset-4 col-sm-8 col-sm-offset-2"/><img src="#url.logo"></div>
<form class="form-horizontal" method="post" role="form">
<div class="form-group">
<label class="control-label col-sm-3" for="username">Логин:</label>
<div class="col-sm-9">
<input type="text" class="form-control" name="username" id="username" placeholder="Логин">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-3" for="email">Email:</label>
<div class="col-sm-9">
<input type="email" class="form-control" name="email" id="email" placeholder="Email">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-3" for="pwd1">Пароль</label>
<div class="col-sm-9">
<input type="password" class="form-control" name="pwd1" id="pwd1" placeholder="Введите пароль">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-3" for="pwd2">Повторите пароль:</label>
<div class="col-sm-9">
<input type="password" class="form-control" name="pwd2" id="pwd2" placeholder="Повторите пароль">
</div>
</div>
<?php wp_nonce_field( 'post_nonce', 'post_nonce_field' ); ?>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9" style="text-align:center;">
<button type="submit" class="btn btn-primary">Зарегистрироваться</button>
<input type="hidden" name="task" value="register" /><br/>
</div>
</div>
</form>
</div>
</div>
</div>
<?php
get_footer();
?>
<div class="message">
<?php
$login = (isset($_GET['login']) ) ? $_GET['login'] : 0;
if ( $login === "failed" ) {
echo '<strong>Ошибка</strong> Неверный логин или пароль!';
} elseif ( $login === "empty" ) {
echo '<strong>Ошибка:</strong>Логин или пароль не могут быть пустыми.';
} elseif ( $login === "false" ) {
echo '<strong>ОШИБКА:</strong> Выход';
}
?>
</div>
<?php } ?>
Пример моей кастомной страницы входа. Сохраните как login.php и вставьте код
add_action('init','wpse_login');
function wpse_login(){
global $pagenow;
if( 'wp-login.php' == $pagenow && !is_user_logged_in()) {
wp_redirect('http://yoursite.com/login.php');
exit();
}
}
в файл functions.php

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

Этот код заменяет wp-login.php на login.php с моим пользовательским кодом на основе Bootstrap. Это может предотвратить автоматические боты или угадывание стандартного URL. Вы можете изменить <i>login</i> на любое слово, которое захотите, и никто не будет знать прямой URL для входа, кроме вас.

add_action('check_admin_referer', 'logout_without_confirm', 10, 2); function logout_without_confirm($action, $result) { /* * Разрешает выход без подтверждения / if ($action == "log-out" && !isset($_GET['_wpnonce'])) { $redirect_to = isset($_REQUEST['redirect_to']) ? $_REQUEST['redirect_to'] : 'https://yourdomain.com'; $location = str_replace('&', '&', wp_logout_url($redirect_to)); header("Location: $location"); die; } }
