Come validare un utente esternamente a WordPress/PHP?
Sto lavorando su un'applicazione AJAX che sarà incorporata in una pagina WordPress. L'app AJAX scambia dati con servlet in esecuzione su Tomcat. Ora le servlet hanno bisogno di un modo per determinare se una richiesta proviene da un utente loggato in WordPress. Se l'utente è loggato, le servlet devono anche poter determinare l'ID utente per poter interrogare il database. Se l'utente non è loggato, la richiesta verrà rifiutata.
In altre parole, ho bisogno che una servlet esegua una richiesta solo se l'utente che l'ha causata è loggato in WordPress (versione 3.3.x). Sia la servlet (Tomcat) che WordPress (Apache2) sono in esecuzione sulla stessa macchina fisica e condividono lo stesso database.
In teoria questo potrebbe essere facilmente risolto facendo quanto segue:
- Durante il login di WordPress, un token utente viene memorizzato in una variabile JavaScript.
- L'app AJAX inoltra il token utente alle servlet ad ogni chiamata.
- Le servlet usano il token per verificare con WordPress se è valido (cioè se l'utente è loggato) ed eseguire o rifiutare la richiesta.
La domanda è: come può essere implementato questo lato WordPress?
Perché, ciò che rende complicata la teoria è il fatto che non ho ancora fatto alcuna programmazione PHP.
Inizialmente ho pensato di trasmettere il cookie wordpress_logged_in (auth) alla servlet e far sì che la servlet interroghi WordPress per verificare se il cookie auth è ancora valido. Ma a quanto pare, questo non può essere fatto, poiché wp_validate_auth_cookie() fallisce sempre, anche se vengono passati i dati del cookie di un utente loggato. Un'altra soluzione potrebbe essere sviluppare un plugin che memorizzi sessionid e userid in una tabella, che potrebbe essere facilmente interrogata dalle servlet. O forse c'è un'altra soluzione...

WordPress ha già un'API integrata tramite un server XMLRPC. Ciò significa che puoi effettuare una richiesta XMLRPC dalla tua applicazione Java e verificare un nome utente/password. Sfortunatamente, non è possibile autenticarsi direttamente così com'è.
Detto questo, è molto semplice crearne una tua. Basta agganciarsi al filtro xmlrpc_methods
e aggiungere il tuo. La chiave dell'array che aggiungi sarà il metodo XMLRPC che chiami dalla tua app, e il valore sarà la funzione che viene chiamata dal server XMLRPC di WordPress.
<?php
add_filter('xmlrpc_methods', 'wpse39662_add_login_method' );
/**
* Filtra i metodi XMLRPC per consentire solo la verifica del login/password
* di un determinato utente
*/
function wpse39662_add_login_method( $methods )
{
$methods['wpse39662.login'] = 'wpse39662_check_login';
return $methods;
}
E la funzione di callback, wpse39662_check_login
, riceverà un argomento, l'array di elementi inviati al server XMLRPC.
<?php
function wpse39662_check_login( $args )
{
$username = $args[0];
$password = $args[1];
$user = wp_authenticate( $username, $password );
if( is_wp_error( $user ) )
{
return false;
}
return true;
}
Ecco tutto questo come plugin. Con questo installato e XMLRPC abilitato sul tuo sito WP, dovresti essere in grado di effettuare richieste con un client XMLRPC (sono sicuro che Java ne abbia uno).
Ecco il codice che ho usato per testare quanto sopra (client XMLRPC Python).
>>> import xmlrpclib as xmlrpc
>>> s = xmlrpc.ServerProxy('http://wordpress.dev/xmlrpc.php')
>>> s.wpse39662.login('admin', 'password')
True

Grazie! Questo mi fa fare un enorme passo avanti! È possibile ottenere lo stesso risultato utilizzando il cookie di autenticazione dell'utente? Così non devo archiviare e inviare username/password attraverso la rete. Il mio progetto consiste in un'app AJAX incorporata in una pagina WordPress. L'app AJAX chiama un servlet e il servlet chiede a WordPress se l'utente è autenticato. Potrei passare user/pwd all'app AJAX e trasferirli al servlet, ma temo che non sarebbe molto sicuro. Quindi ho provato a passare il contenuto del cookie di autenticazione a wp_validate_auth_cookie() ma fallisce sempre.

WordPress (attualmente) verifica se l'utente è ancora loggato controllando uno dei cookie che rilascia al momento del login. Costruisce il contenuto di questo cookie eseguendo alcuni hash. I dettagli sono nella funzione "wp_generate_auth_cookie" in /wp-includes/pluggable.php:
function wp_generate_auth_cookie($user_id, $expiration, $scheme = 'auth') {
$user = get_userdata($user_id);
$pass_frag = substr($user->user_pass, 8, 4);
$key = wp_hash($user->user_login . $pass_frag . '|' . $expiration, $scheme);
$hash = hash_hmac('md5', $user->user_login . '|' . $expiration, $key);
$cookie = $user->user_login . '|' . $expiration . '|' . $hash;
return apply_filters('auth_cookie', $cookie, $user_id, $expiration, $scheme);
}
Puoi ricreare questo algoritmo (usando questa e le altre funzioni auth_cookie) nel tuo codice Java per eseguire gli stessi controlli. JS potrebbe essere usato per assicurarsi che il cookie venga inviato al tuo servlet.
In alternativa XMLRPC potrebbe essere una buona idea. Potresti scrivere un nuovo metodo (come spiegato in un'altra soluzione qui) per validare il cookie di autenticazione (invece di validare username e password come si fa di solito).

Scarica il plugin Exec-PHP, quindi crea una pagina WordPress (non un articolo) con un permalink appropriato (http://mysite/user_id/
) e inserisci il codice presente nella documentazione dell'API get_current_user_id()
:
<?php
$user_id = get_current_user_id();
if ($user_id == 0) {
echo 'Al momento non sei loggato.';
} else {
echo 'Sei loggato come utente '.$user_id.'.';
}
?>
A questo punto puoi estrarre i cookie inviati dal client e inserirli in una richiesta GET
per http://127.0.0.1/user_id/
. In questo modo saprai se l'utente è loggato e qual è il suo ID utente.

Grazie per la risposta, il problema è che i servlet sono scritti in Java, quindi il codice PHP non può essere eseguito. Quello che sto cercando è una sorta di interfaccia esterna che permetta a un servlet/Java di comunicare con WordPress/PHP. Sicuramente esiste qualche tipo di interfaccia disponibile, ma non riesco a trovarla...

Ah, capisco. Forse utilizzare qualcosa come Quercus http://www.caucho.com/resin-3.0/quercus/ potrebbe darti il meglio di entrambi i mondi?

Grazie, ma Quercus non è la soluzione giusta, dato che ho già un'installazione funzionante di WordPress/PHP/Apache e un'installazione funzionante di servlet/Java/Tomcat. Ora l'unica cosa che mi serve è un'interfaccia tra questi due, che permetta al servlet di verificare se un utente è loggato in WordPress (qualche interfaccia/protocollo/IPC/qualsiasi cosa).

Questo è un plugin WordPress in un singolo file che fa il lavoro:
function yournamespace_validateAuthCookie($cookie, $scheme = 'logged_in') {
return wp_validate_auth_cookie($cookie, $scheme);
}
function yournamespace_new_xmlrpc_methods($methods) {
$methods['yournamespace.validateAuthCookie'] = 'yournamespace_validateAuthCookie';
return $methods;
}
add_filter('xmlrpc_methods', 'yournamespace_new_xmlrpc_methods');
In sostanza, espone un nuovo metodo XML-RPC con cui puoi chiedere a WordPress di validare il cookie wordpress_logged_in_...
.
Successivamente, devi scrivere del codice per interrogare questo metodo e passargli il valore del cookie wordpress_logged_in_...
.
Questo metodo restituirà false
(se il cookie non è valido) oppure l'ID dell'utente se la validazione ha successo.
