Cómo verificar usuario/contraseña sin iniciar sesión del usuario
Estoy escribiendo un plugin que crea un endpoint de API que valida pares de usuario/contraseña.
Actualmente estoy usando wp_signon()
para verificar si la combinación de usuario/contraseña funciona. Esto funciona bien cuando las credenciales fallan porque devuelve un objeto de error. Pero cuando las credenciales son correctas, automáticamente inicia sesión con ese usuario, por lo que mi endpoint devuelve una página completa.
El codex actualmente ni siquiera menciona el hecho de que automáticamente inicia sesión del usuario. Tampoco parece aceptar un parámetro para suprimir esa funcionalidad. Para mis propósitos un simple booleano estaría bien.
ACTUALIZACIÓN: Tuve que elegir una única respuesta, pero había mucha información útil en varias de las otras respuestas que intentaré resumir brevemente aquí...
EXISTE una función que hace exactamente lo que estaba tratando de hacer:
wp_authenticate($username, $password)
SIN EMBARGO, viene con una desventaja. Establecerá automáticamente las cookies de inicio de sesión, lo que puede crear problemas en una situación como la mía. Así que ten cuidado. Esta función no está actualmente en el codex.La mejor opción para lo que estoy haciendo es
wp_authenticate_username_password($user, $username, $password)
porque NO establece las cookies de inicio de sesión. Esta función está más documentada, pero el detalle REALMENTE importante que no estaba en el codex es que puedes pasarNULL
como primer parámetro. Esto significa que puedes efectivamente usarla para hacer exactamente comowp_authenticate()
sin preocuparte de que las cookies se estropeen. Lee la documentación para que no te confundas con la respuesta. Devuelve un objeto WP_User o un WP_Error (¡no un booleano!).

Hay una función en los user.php
de los archivos principales llamada wp_authenticate_username_password
que parece ser lo que estás buscando.
Si deseas evitar pasar el objeto $user
(probablemente solo tengas el nombre de usuario + contraseña), entonces simplemente pasa null
como primer argumento de la función:
$check = wp_authenticate_username_password( NULL, 'some_username', '#thepassw0rd' );
Luego puedes verificar el resultado simplemente con is_wp_error( $check )
.

Esto no hace lo que parece. Es un error común (que yo también he cometido). Sin embargo, acabo de descubrir una función que realmente hace lo que queremos. Mira mi respuesta...

@kaiser "Vaya". Nunca me di cuenta de que podías pasar NULL como primer parámetro. Es bueno saberlo. También echa un vistazo a wp_authenticate()
(ver mi respuesta). Lo acabo de encontrar después de semanas de búsqueda.

Usa,
y
Explicación
// obtener usuario por login mediante el nombre de usuario proporcionado (input del formulario)
$user = get_user_by('login', $username);
// asignar ID de usuario basado en el nombre de login
$user_id = $user->ID;
// obtener datos del usuario pasando la variable $user_id a get_userdata
// que devuelve el objeto de usuario y gran cantidad de información relacionada para acceder
$user_data = get_userdata($user_id);
// asignar el nombre de usuario y contraseña a variables
$user_login = $user_data->user_login;
$user_pass = $user_data->user_pass;
// verificar el nombre de usuario/contraseña contra los valores enviados
if ($user_login = $username && $user_pass = $password) {
// hacer algo...
Notas
$username
debería validarse como verdadero por defecto, de lo contrario no se habría devuelto un objeto de usuario si el$username
proporcionado no coincidía con uno existente en la base de datos. Por lo tanto, la validación depende entonces de la variable$password
que almacena el input del formulario proporcionado por el usuario.Podría haber una forma más eficiente de lograr esto, ya sea acortando el código existente o usando otras funciones de la API.
ACTUALIZACIÓN
Basado en la sugerencia de fdsa podrías usar wp_authenticate_username_password
de esta manera,
$auth = wp_authenticate_username_password($user, $username, $password);
if (!$auth->user_login = $username && !$auth->user_pass = $password) {
echo 'no autenticado';
} else {
echo 'autenticado';
}
Pero incluso mejor que eso,
$auth = wp_authenticate_username_password($user, $username, $password);
if (is_wp_error($auth)) {
echo 'no autenticado';
} else {
echo 'autenticado';
}
Realmente el crédito/respuesta marcada debería darse a fdsa por el método más eficiente mediante una función (tristemente) no documentada del núcleo de WP.

Descargo de responsabilidad: Esta respuesta solo pretende mostrar lo que ocurre detrás de escena y no es un ejemplo real de cómo hacer las cosas.
Traza de ejecución
wp_signon()
llama a wp_set_auth_cookie()
, que a su vez llama a wp_generate_auth_cookie()
. El resultado se utilizará dentro de setcookie()
como segundo argumento.
(No performante) diversión con filtros
También conocido como engañar a WordPress de la manera incorrecta.
Podrías entonces entrar en el filtro 'auth_cookie'
dentro de wp_generate_auth_cookie()
y simplemente establecerlo como nulo o algo diferente al valor de SECURE_AUTH_COOKIE
o AUTH_COOKIE
. Esto te dejará con una cookie sin sentido, que no puede iniciar sesión.

"¡Listo!": wp_authenticate($username, $password)
No aparece en el codex, pero puedes buscarlo en wpseek.
Hace exactamente lo que parece. Toma un nombre de usuario y contraseña en texto plano y devuelve ya sea un objeto WP_User
o un WP_Error
... y NO inicia sesión de nadie.
¡Una advertencia importante! Lo siguiente SIEMPRE devolverá verdadero (porque la función devuelve un objeto en cualquier caso):
$auth = ( wp_authenticate($username, $password) ) ? TRUE : FALSE;
Probablemente querrás hacer algo como esto:
$test_creds = wp_authenticate($username, $pass);
$class = get_class($test_creds);
$auth = ( $class == 'WP_User' ) ? TRUE : FALSE;
Espero que esto le ayude a alguien.

Puedes usar instanceof
o is_a()
para verificar si es un WP_User
. También podrías simplemente usar una de las funciones anteriores y eliminar el filtro en authenticate
...

Se recomienda usar is_wp_error($auth)
que devolverá TRUE
si falla la autenticación y FALSE
si la autenticación es exitosa.

Una nota más: Esto no te iniciará sesión, pero aún así dejará la cookie establecida, ya que la función llama al filtro `'authenticate`. Si optas por esa solución, debes asegurarte de que se eliminen todas las devoluciones de llamada del filtro. De lo contrario, el cielo podría caerte encima :)

Es bueno saberlo. ¿Acaso wp_authenticate_username_password( NULL, 'some_username', '#thepassw0rd' );
tiene el mismo problema? ¿Podrías elaborar un poco más sobre lo del "cielo cayéndose"? ¿Qué es lo que podría salir mal?

Nota: En lugar de usar wp_authenticate
, en realidad quieres usar user_pass_ok($user_login, $user_pass)
, que a su vez utiliza wp_authenticate
ya que es la función envoltorio adecuada que devuelve true/false
. Sin embargo, como dijo @kaiser, la cookie se establece mediante el filtro authenticate
. La función wp_authenticate_username_password
no parece establecer la cookie.

Según la documentación, wp_authenticate()
SÍ inicia sesión del usuario si las credenciales son correctas. Curiosamente, no lo hace en mi caso.
