En este post te mostraré cómo autenticar un usuario existente de WordPress desde un lugar externo; es decir, desde otro sistema, software, código o como le quieras llamar.
Dicho con otras palabras, te mostraré cómo hacer un login externo usando el usuario y contraseña de los usuarios de WordPress.
Por ejemplo, yo tengo un sistema en el que quiero autenticar a los usuarios con los que ya tengo en mi WordPress, así que quiero reutilizar esa tabla de usuarios y verificar si la contraseña y usuario coinciden, sin usar las funciones de WordPress.
Requisitos para leer base de datos de WordPress
Esto lo vamos a hacer con PHP, pero técnicamente hablando se podría hacer desde cualquier lenguaje de programación que pueda conectarse a MySQL y usar el algoritmo de hasheo de WP.
Para que funcione con PHP, el programa debe estar en el mismo servidor que el sitio de WordPress, y si no, al menos la base de datos debe estar disponible de manera remota.
Comprobar contraseña de WordPress
Esto es como hacer un login simple, lo que va a cambiar será el modo de comprobar si la contraseña es correcta, pues vamos a usar PasswordHash: Portable PHP password hashing framework.
Puedes descargarlo desde la página oficial, e incluirlo como mejor lo prefieras.
Obteniendo base de datos
En este caso usaré PDO para obtener una conexión a la base de datos. Recuerda cambiar las credenciales como sea necesario.
<?php
function obtenerBaseDeDatosWordPress()
{
$pass = "";
$usuario = "root";
$nombreBaseDeDatos = "wp";
$baseDeDatos = new PDO('mysql:host=localhost;dbname=' . $nombreBaseDeDatos, $usuario, $pass);
$baseDeDatos->query("set names utf8;");
$baseDeDatos->setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE);
$baseDeDatos->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$baseDeDatos->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
return $baseDeDatos;
}
Como puedes ver es una simple conexión a la base de datos de MySQL de WordPress en donde están almacenados los usuarios.
Obtener usuario de WordPress
Ahora que tenemos la conexión, vamos a leer los datos. Los usuarios están en wp_users
(me parece que puede cambiar si cambiaste el prefijo de las tablas, así que podría ser simplemente users
) y sus roles (administrador, suscriptor, colaborador) están en wp_usermeta
por lo que la consulta y la función quedan así:
<?php
function obtenerUsuarioDeWordPress($usuarioOCorreo)
{
$bd = obtenerBaseDeDatosWordPress();
$sentencia = $bd->prepare("SELECT * FROM wp_users
INNER JOIN wp_usermeta ON wp_users.ID = wp_usermeta.user_id
WHERE (wp_users.user_login = ? OR wp_users.user_email = ?) AND wp_usermeta.meta_key = ?");
$sentencia->execute([$usuarioOCorreo, $usuarioOCorreo, "wp_capabilities"]);
return $sentencia->fetchObject();
}
En este caso el usuario puede autenticarse con el correo o con el nombre de usuario. La función regresará un objeto de usuario que tendrá todos los datos del mismo.
Aquí hay algo muy importante y es que el rol está dentro de meta_value
pero este valor está serializado así que debemos usar unserialize
y hacer un montón de comprobaciones para saber el rol.
Autenticar usuario
Ahora que ya tenemos esa función, veamos cómo autenticar. Lo que hacemos es:
- Obtener el usuario de la base de datos de WordPress
- Incluir a PasswordHash para comprobar la contraseña
- Si todo es correcto, volvemos a regresar al usuario, con el rol ya arreglado
- Si algo falla (la contraseña no es correcta, no existe el usuario, etcétera) regresamos
false
Entonces queda así:
<?php
function autenticarUsuario($username, $password)
{
# Obtener usuario. Si no existe, regresamos false inmediatamente
$usuario = obtenerUsuarioDeWordPress($username);
if (!$usuario) return false;
# Incluimos PasswordHash pues vamos a realizar algunas comprobaciones
include_once "PasswordHash.php";
# Esta es la contraseña almacenada en la base de datos:
$storedHash = $usuario->user_pass;
# Crear instancia de PasswordHash
$passwordHash = new PasswordHash(8, false);
$metaValue = unserialize($usuario->meta_value);
# Nota: en mi caso solo permito usuarios administradores y colaboradores; ignoro a los demás.
# Si tú quieres permitirlos, modifica el código
if (!isset($metaValue["administrator"]) && !isset($metaValue["contributor"])) {
return false;
}
if ((isset($metaValue["administrator"]) && !$metaValue["administrator"]) && (isset($metaValue["contributor"]) && !$metaValue["contributor"])) {
return false;
}
# Ahora sí comprobamos la contraseña plana ($password) con la hasheada almacenada ($storedHash)
if ($passwordHash->CheckPassword($password, $storedHash)) {
# Si llegamos aquí, el usuario y contraseña son correctos
# Lo único que hacemos es poner el rol del mismo
if ((isset($metaValue["administrator"])) && $metaValue["administrator"]) {
$usuario->role = "administrator";
} else if (isset($metaValue["contributor"]) && $metaValue["contributor"]) {
$usuario->role = "contributor";
}
# Y regresamos el usuario
return $usuario;
} else {
# Caso contrario (la contraseña no coincide) regresamos igualmente false
return false;
}
}
La función recibe el nombre de usuario o correo, y la contraseña plana. Obtiene el usuario, comprueba los datos y en caso de que todo vaya bien, regresará el usuario.
Si la contraseña no coincide o el usuario no existe, regresa false
. A partir de la llamada de esta función podríamos iniciar sesión, pues si nos regresa un usuario podemos iniciar y establecer datos en la sesión.
A continuación te mostraré un ejemplo de uso de la función.
Poniendo todo junto
También he grabado un vídeo explicando el código, te invito a verlo y a que te suscribas:
Veamos el ejemplo completo, a continuación el código. Recuerda que la clase PasswordHash.php debe estar en el mismo directorio que este código.
<?php
/*
____ _____ _ _ _
| _ \ | __ \ (_) | | |
| |_) |_ _ | |__) |_ _ _ __ _____| |__ _ _| |_ ___
| _ <| | | | | ___/ _` | '__|_ / | '_ \| | | | __/ _ \
| |_) | |_| | | | | (_| | | / /| | |_) | |_| | || __/
|____/ \__, | |_| \__,_|_| /___|_|_.__/ \__, |\__\___|
__/ | __/ |
|___/ |___/
____________________________________
/ Si necesitas ayuda, contáctame en \
\ https://parzibyte.me /
------------------------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Creado por Parzibyte (https://parzibyte.me). Este encabezado debe mantenerse intacto,
excepto si este es un proyecto de un estudiante.
*/
function obtenerBaseDeDatosWordPress()
{
$pass = "";
$usuario = "root";
$nombreBaseDeDatos = "wp";
$baseDeDatos = new PDO('mysql:host=localhost;dbname=' . $nombreBaseDeDatos, $usuario, $pass);
$baseDeDatos->query("set names utf8;");
$baseDeDatos->setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE);
$baseDeDatos->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$baseDeDatos->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
return $baseDeDatos;
}
function obtenerUsuarioDeWordPress($usuarioOCorreo)
{
$bd = obtenerBaseDeDatosWordPress();
$sentencia = $bd->prepare("SELECT * FROM wp_users
INNER JOIN wp_usermeta ON wp_users.ID = wp_usermeta.user_id
WHERE (wp_users.user_login = ? OR wp_users.user_email = ?) AND wp_usermeta.meta_key = ?");
$sentencia->execute([$usuarioOCorreo, $usuarioOCorreo, "wp_capabilities"]);
return $sentencia->fetchObject();
}
function autenticarUsuario($username, $password)
{
# Obtener usuario. Si no existe, regresamos false inmediatamente
$usuario = obtenerUsuarioDeWordPress($username);
if (!$usuario) return false;
# Incluimos PasswordHash pues vamos a realizar algunas comprobaciones
include_once "PasswordHash.php";
# Esta es la contraseña almacenada en la base de datos:
$storedHash = $usuario->user_pass;
# Crear instancia de PasswordHash
$passwordHash = new PasswordHash(8, false);
$metaValue = unserialize($usuario->meta_value);
# Nota: en mi caso solo permito usuarios administradores y colaboradores; ignoro a los demás.
# Si tú quieres permitirlos, modifica el código
if (!isset($metaValue["administrator"]) && !isset($metaValue["contributor"])) {
return false;
}
if ((isset($metaValue["administrator"]) && !$metaValue["administrator"]) && (isset($metaValue["contributor"]) && !$metaValue["contributor"])) {
return false;
}
# Ahora sí comprobamos la contraseña plana ($password) con la hasheada almacenada ($storedHash)
if ($passwordHash->CheckPassword($password, $storedHash)) {
# Si llegamos aquí, el usuario y contraseña son correctos
# Lo único que hacemos es poner el rol del mismo
if ((isset($metaValue["administrator"])) && $metaValue["administrator"]) {
$usuario->role = "administrator";
} else if (isset($metaValue["contributor"]) && $metaValue["contributor"]) {
$usuario->role = "contributor";
}
# Y regresamos el usuario
return $usuario;
} else {
# Caso contrario (la contraseña no coincide) regresamos igualmente false
return false;
}
}
# Momento de probar. Usaré <pre> para que se vea de mejor manera, pero recuerda que solo estoy depurando ;)
echo "<pre>";
echo "Debería mostrar los datos correctos: ";
$usuarioCorrecto = autenticarUsuario("parzibyte", "hunter2");
echo json_encode($usuarioCorrecto, JSON_PRETTY_PRINT);
echo "\n\nAhora debería mostrar false: ";
$usuarioIncorrecto = autenticarUsuario("inexistente", "blabla");
echo json_encode($usuarioIncorrecto, JSON_PRETTY_PRINT);
echo "</pre>";
Igualmente dejo el código completo en mi GitHub. No olvides cambiar las credenciales de la base de datos. Aquí puedes leer más artículos de WordPress.
Buen post! Estoy tratando de hacer login con un usuario de WordPress en un php externo, como el que has puesto. El caso es que, he probado lo que mencionas y nos muestras en el post pero no me funciona (he cambiado el usuario + passwd evidentemente). La salida de la web es esta:
DeberÃa mostrar los datos correctos: false
Ahora deberÃa mostrar false: false
El login me funciona correctamente en el WordPress..se te ocurre que puede ocurrir?
Saludos!
Hola. Para consultas personalizadas puede escribirme en https://parzibyte.me#contacto
Saludos!