Contents
Introducción — objetivo y alcance
Este artículo explica, con todo lujo de detalles, cómo detectar desde JavaScript si un visitante de un sitio WordPress está autenticado y cómo exponer esa información de forma segura (sin filtrar datos sensibles). Se muestran tres enfoques prácticos, sus ventajas/desventajas y recomendaciones de seguridad para evitar fugas de información y ataques CSRF/XSS/CORS.
Aclaración sobre seguridad y modelo de amenazas
- Qué se quiere conseguir: que código cliente (JS) conozca si el usuario está logueado y, opcionalmente, reciba sólo datos no sensibles (por ejemplo: id público, display_name o roles de forma muy limitada).
- Qué NO se debe hacer: incrustar en el frontend datos sensibles (passwords, tokens privados, emails no públicos, meta sensibles), exponer endpoints REST sin control de permisos o CORS, y generar variables globales con información privada.
- Requisitos seguros: siempre HTTPS, validación en servidor de permisos, uso de nonces para llamadas que mutan o recuperan datos sensibles, y mínimo privilegio en los datos devueltos.
Resumen de métodos
- Pasar un booleano seguro al script encolado (wp_localize_script / wp_add_inline_script). Opción simple, buena para UI condicional.
- Consultar una ruta REST personalizada que valida autenticación y devuelve solo campos permitidos. Opción RESTful y flexible.
- Usar admin-ajax con acciones protegidas por check_ajax_referer y comprobaciones de capacidad. Opción retrocompatible.
1) Método simple: booleano seguro inyectado en el script
Este enfoque consiste en encolar tu script y pasarle una estructura mínima con un booleano que indique si el usuario está logueado. Nunca incluyas más que lo estrictamente necesario.
Ejemplo: functions.php (enqueue datos seguros)
// functions.php function miplugin_enqueue_scripts() { wp_enqueue_script( miplugin-frontend, plugin_dir_url(__FILE__) . assets/js/miplugin-frontend.js, array(), 1.0, true ) // Solo pasamos un booleano (evitar datos sensibles) data = array( isLoggedIn => is_user_logged_in() ) // wp_localize_script convierte a objeto JS de forma segura wp_localize_script(miplugin-frontend, MiPluginData, data) } add_action(wp_enqueue_scripts, miplugin_enqueue_scripts)
Ejemplo: JavaScript que consume la variable
// assets/js/miplugin-frontend.js if (typeof MiPluginData !== undefined MiPluginData.isLoggedIn) { // Cambiar comportamiento visual sin exponer datos del usuario document.documentElement.classList.add(user-logged-in) } else { document.documentElement.classList.remove(user-logged-in) }
Pros/Contras
- Pros: sencillo, sin llamadas adicionales, buena para ajustar interfaz.
- Contras: solo informa si hay sesión no sirve para obtener datos adicionales sobre el usuario sin crear endpoints adicionales seguros.
2) Método REST seguro: ruta personalizada con comprobaciones
Para obtener información adicional no sensible (por ejemplo display_name o ID público) pero manteniendo control, registre una ruta REST que valide permisos y devuelva solo campos permitidos. Use nonces o la cabecera X-WP-Nonce que WordPress espera para peticiones autenticadas desde el frontend.
Registrar la ruta REST (PHP)
// functions.php o plugin principal add_action(rest_api_init, function () { register_rest_route(miplugin/v1, /me, array( methods => GET, callback => miplugin_rest_get_me, permission_callback => function () { // Solo usuarios autenticados pueden acceder a esta ruta return is_user_logged_in() }, )) }) function miplugin_rest_get_me( request ) { user = wp_get_current_user() // Devolver solo campos no sensibles return array( id => user->ID, display_name => user->display_name, // No devolver email ni meta sensibles a menos que sea imprescindible ) }
Pasar nonce al frontend (opcional pero recomendado)
// functions.php: encolar script y pasar nonce para peticiones REST autenticadas function miplugin_enqueue_with_nonce() { wp_enqueue_script(miplugin-frontend, plugin_dir_url(__FILE__) . assets/js/miplugin-frontend.js, array(), 1.0, true) data = array( restUrl => esc_url_raw( rest_url(miplugin/v1/me) ), nonce => wp_create_nonce(wp_rest) ) wp_localize_script(miplugin-frontend, MiPluginData, data) } add_action(wp_enqueue_scripts, miplugin_enqueue_with_nonce)
Consumir la ruta REST desde JS
// assets/js/miplugin-frontend.js if (typeof MiPluginData !== undefined) { fetch(MiPluginData.restUrl, { method: GET, credentials: same-origin, headers: { X-WP-Nonce: MiPluginData.nonce, Accept: application/json } }) .then(response => { if (!response.ok) throw new Error(No autorizado o error en la petición) return response.json() }) .then(data => { // data: { id, display_name } console.log(Usuario autenticado:, data) }) .catch(err => { // Usuario no autenticado o error console.log(Estado no autenticado o error, err) }) }
Buenas prácticas al usar REST
- Configurar permission_callback que valide is_user_logged_in() y/o capacidades concretas (current_user_can).
- Devolver únicamente los campos que realmente necesitas.
- Proteger con nonces y usar X-WP-Nonce para peticiones desde el frontend.
- No permitir CORS públicos para endpoints que devuelvan datos de usuario.
3) admin-ajax.php y acciones AJAX seguras
Común en desarrollos legacy. Use check_ajax_referer para CSRF y current_user_can/is_user_logged_in para permisos.
Registrar la acción y comprobar nonce
// functions.php add_action(wp_ajax_miplugin_get_me, miplugin_ajax_get_me) // sólo usuarios autenticados function miplugin_ajax_get_me() { check_ajax_referer(miplugin-nonce, security) if (!is_user_logged_in()) { wp_send_json_error(No autenticado, 401) } user = wp_get_current_user() wp_send_json_success(array( id => user->ID, display_name => user->display_name )) }
JS que llama a admin-ajax
// Encolar y pasar nonce similar con wp_localize_script fetch(ajaxurl, { method: POST, credentials: same-origin, headers: { Content-Type: application/x-www-form-urlencoded charset=UTF-8 }, body: new URLSearchParams({ action: miplugin_get_me, security: MiPluginData.nonce }) }) .then(r => r.json()) .then(resp => { if (resp.success) { console.log(Usuario:, resp.data) } else { console.log(No autenticado o error) } })
Recomendaciones de seguridad detalladas
- Minimizar datos: siempre enviar lo mínimo imprescindible. Un booleano muchas veces es suficiente.
- Validación en servidor: nunca confíes en el estado informado por JS. Todas las decisiones sensibles se deben validar en servidor.
- Nonces y CSRF: para acciones que cambien estado o devuelvan datos con riesgo, use check_ajax_referer o X-WP-Nonce en peticiones REST.
- HTTPS: obligatorio para proteger cookies de sesión y evitar MITM.
- Cookies seguras: marque cookies de autenticación como HttpOnly (lo hace WP para algunas cookies) y SameSite según necesidad.
- Escapar y sanitizar: use esc_html, esc_attr y wp_json_encode cuando inyecte datos en JS evite concatenación insegura.
- CORS: no permita orígenes no confiables para endpoints que devuelvan datos de usuario.
- Audit logs y límites: para endpoints sensibles, registre y limite peticiones (rate limit) y revise logs de auditoría si es necesario.
Errores comunes y cómo evitarlos
- Inyectar email/password/token en window.: nunca lo haga. Use sólo banderas o datos públicos mínimos.
- REST sin permission_callback: Evítelo eso permitirá que cualquier visitante acceda a la ruta.
- Depender solo de JS para control de acceso: el frontend es manipulable todas las comprobaciones aplicativas deben ocurrir en servidor.
Checklist rápido antes de publicar
- ¿Solo paso un booleano o datos no sensibles? Sí/No
- ¿Las rutas que devuelven información tienen permission_callback adecuada? Sí/No
- ¿Uso HTTPS y nonces para llamadas autenticadas? Sí/No
- ¿He revisado que no expondré metadata sensible en JSON? Sí/No
Conclusión
Detectar si un usuario está logueado desde JavaScript en WordPress es sencillo si se hace con prudencia. Para cambios visuales basta con pasar un booleano seguro vía wp_localize_script para información adicional use rutas REST o admin-ajax protegidas con nonces y permission callbacks. La clave es exponer lo mínimo, validar todo en el servidor y blindar las llamadas con HTTPS y controles de acceso.
|
Acepto donaciones de BAT's mediante el navegador Brave 🙂 |