Reindirizzare l'utente usando l'hook 'wp_login_failed' se l'errore è 'empty_username' o 'empty_password'

18 dic 2014, 12:20:18
Visualizzazioni: 16.7K
Voti: 7

Contesto

Sto cercando di creare un login frontend senza interruzioni per un blog, mantenendo comunque disponibile wp-login.php per gli utenti che sanno come accedervi. wp-login.php è anche necessario per autenticare i login frontend, quindi non può essere rimosso completamente.

Ci sono quasi riuscito, ma ho un problema con i login falliti, in particolare con un username vuoto.

Domanda

Qualcuno conosce un modo per evitare che wp-login.php venga visualizzato per errori di username/password vuoti, evitando al contempo che venga mostrato un errore quando un utente accede direttamente a wp-login.php?

Il mio lavoro

Ho individuato l'hook wp_login_failed e creato la funzione seguente. In pratica aggiunge parametri alla query per indicare che il login è fallito e quale username è stato inserito, prima di reindirizzare l'utente alla pagina di login frontend. Con questi parametri posso determinare perché il login è fallito e mostrare un messaggio all'utente.

add_action('wp_login_failed', 'djg_front_end_login_fail');
function djg_front_end_login_fail($username){

    $referrer = (isset($_SERVER['HTTP_REFERER'])) ? $_SERVER['HTTP_REFERER'] : $_SERVER['PHP_SELF'];
    $referrer = add_query_arg('result', 'failed', $referrer);
    $referrer = add_query_arg('username', $username, $referrer);

    if(!empty($referrer) && !strstr($referrer, 'wp-login') && !strstr($referrer, 'wp-admin')) :
        wp_redirect($referrer);
        exit;
    endif;

}

Tuttavia, ho notato che se il campo username era vuoto non venivo reindirizzato e all'utente veniva ancora mostrato wp-login.php.

Analizzando meglio ho trovato la funzione wp_authenticate() dove ho notato che se il primo errore di login era empty_username o empty_password, l'hook wp_login_failed non veniva attivato. Per ovviare a questo, ho utilizzato l'hook filter authenticate modificando il codice di questi errori, anteponendo djg_ a loro, in modo che non venissero ignorati.

add_filter('authenticate', 'djg_authenticate_login', 99, 3);
function djg_authenticate_login($user, $username, $password){;

    if(is_wp_error($user)) :

        $codes = $user->get_error_codes();
        $messages = $user->get_error_messages();

        $user = new WP_Error;

        for($i = 0; $i <= count($codes) - 1; $i++) :

            $code = $codes[$i];
            if(in_array($code, array('empty_username', 'empty_password'))) :
                $code = 'djg_' . $code;
            endif;

            $user->add($code, $messages[$i]);

        endfor;

    endif;

    return $user;

}

Questo funziona, ma ora se l'utente accede direttamente alla pagina wp-login.php, che deve rimanere disponibile (come descritto nel Contesto), viene visualizzato un errore -

ERRORE: Il campo username è vuoto.
ERRORE: Il campo password è vuoto.

Infine, dopo molte difficoltà, ho trovato nella funzione wp_signon() il codice che causava questo comportamento, ma non vedo alcun filtro che permetta di modificarlo. In pratica dice che se gli errori sono esattamente empty_username e empty_password, ignorarli. -

if ( is_wp_error($user) ) {
    if ( $user->get_error_codes() == array('empty_username', 'empty_password') ) {
        $user = new WP_Error('', '');
    }

    return $user;
}

Dettagli

  • wp_authenticate() si trova in /wp-includes/pluggable.php
  • L'hook filter authenticate si trova all'interno della funzione wp_authenticate()
  • L'hook action wp_login_failed si trova all'interno della funzione wp_authenticate()
  • wp_signon() si trova in /wp-includes/user.php

Domanda (di nuovo)

Qualcuno conosce un modo per evitare che wp-login.php venga visualizzato per errori di username vuoti, evitando al contempo che venga mostrato un errore quando un utente accede direttamente a wp-login.php?

0
Tutte le risposte alla domanda 1
3

WordPress gestisce il login fallito in due modi:

  1. Se si tratta di credenziali errate e sia username che password hanno un valore, allora questa azione può essere catturata da wp_login_failed
  2. Se entrambi o uno dei campi sono vuoti, WordPress genera l'oggetto errore come primo parametro nel filtro authenticate; non attiva e l'azione wp_login_failed non cattura questa causa/evento

Per quello che abbiamo fatto qui, vedi i commenti nel codice:

add_filter( 'authenticate', function( $user, $username, $password ) {
    // forza la cattura del login fallito per attivare forzatamente l'azione wp_login_failed,
    // in modo che questo evento possa essere catturato
    if ( empty( $username ) || empty( $password ) ) {
        do_action( 'wp_login_failed', $user );
    }
    return $user;
}, 10, 3 );

// per gestire l'evento puoi gestire l'errore come
add_action( 'wp_login_failed', function( $username ) {
    if ( is_wp_error( $username ) ) {
        // esegui operazioni sull'oggetto errore per l'errore vuoto
    }
} );
4 apr 2015 10:53:39
Commenti

Upvotato come buona risposta, ma per favore correggi il problema con l'hook authenticate. Senza passare una priorità e un numero di argomenti, questo sempre attiverà un'azione di login fallito a causa del modo in cui funzionano i filtri e gli hook (per impostazione predefinita, consentono solo un argomento da passare al metodo).

Tom Dyer Tom Dyer
6 mar 2018 14:33:27

Il parametro $username in wp_login_failed è una stringa secondo la documentazione per sviluppatori di wp_login_failed - come otteniamo ora un oggetto di errore da esso?

Cush Cush
15 set 2018 04:19:47

@TomDyer ha ragione, deducendo dalla domanda l'istruzione corretta dovrebbe essere add_filter( 'authenticate', function(...) {...}, 99, 3);

GigiSan GigiSan
17 ott 2018 12:58:25