Auth
Autenticación basada en sesiones, el formulario de inicio de sesión preconstruido y el patrón del complemento de usuario desde la producción.
Nibiru incluye un núcleo de autenticación basado en sesiones (Nibiru\Auth) y un módulo users que te proporciona un formulario de inicio de sesión funcional, una verificación de autorización y el esquema de base de datos en tres comandos.
El núcleo de autenticación
Sección titulada «El núcleo de autenticación»Auth::auth($login, $password) es la llamada de nivel más bajo. Realiza lo siguiente:
- Busca al usuario por
user_login. - Desencripta la contraseña almacenada utilizando el sal de
[SECURITY] password_hash. - Si coincide, reemplaza
$_SESSIONcon['auth' => ['session_id' => …, 'user_id' => …, 'login' => …]].
$auth = new \Nibiru\Auth();if ($auth->auth($_POST['login'], $_POST['password'])) { View::forwardTo('/dashboard');} else { View::assign(['error' => 'Invalid credentials.']);}El módulo de Usuarios
Sección titulada «El módulo de Usuarios»Genera una vez con la CLI:
./nibiru -m usersLuego ejecuta las migraciones correspondientes:
./nibiru -mi localAhora tienes:
application/module/users/— la carpeta del módulo.userstabla — creada por005-user.sql.Userplugin —Nibiru\Module\Users\Plugin\UserconisAuthorized(),loginForm(),currentUser().
Un flujo de inicio de sesión completo
Sección titulada «Un flujo de inicio de sesión completo»application/controller/loginController.php:
<?phpnamespace Nibiru;use Nibiru\Adapter\Controller;use Nibiru\Module\Users\Plugin\User;
class loginController extends Controller{ private User $user;
public function __construct() { parent::__construct(); $this->user = new User(); }
public function pageAction() { if ($this->user->isAuthorized()) { View::forwardTo('/'); return; } View::assign([ 'title' => 'Sign in', 'loginForm' => $this->user->loginForm(), ]); }
public function submitAction() { if ($_SERVER['REQUEST_METHOD'] !== 'POST') return; $auth = new Auth(); if ($auth->auth($_POST['login'] ?? '', $_POST['password'] ?? '')) { View::forwardTo('/'); } else { View::assign(['error' => 'Invalid login.']); } }
public function logoutAction() { unset($_SESSION['auth']); session_regenerate_id(true); View::forwardTo('/login'); }
public function navigationAction() { JsonNavigation::getInstance()->loadJsonNavigationArray(); }}application/view/templates/login.tpl:
{include 'shared/header.tpl'}<body>{include file="navigation.tpl"}<main class="container"> <h1>{$title}</h1> {if $error}<div class="alert alert-danger">{$error}</div>{/if} {$loginForm nofilter}</main>{include 'shared/footer.tpl'}</body>Form::action="/login/submit" está configurado dentro de loginForm() para que el formulario se envíe a la acción correcta.
Protegiendo controladores
Sección titulada «Protegiendo controladores»La verificación sencilla:
public function pageAction() { if (!$this->user->isAuthorized()) { View::forwardTo('/login'); return; } / ...}Para las verificaciones basadas en roles, las aplicaciones de demostración utilizan el complemento Acl del mismo módulo:
use Nibiru\Module\Users\Plugin\Acl;
if (!Acl::can('edit', 'documents')) { View::forwardTo('/forbidden'); return;}Las tablas acl, user_to_acl, acl-data (migraciones 001, 008, 011) forman la base de roles y permisos.
Aumento de la Seguridad
Sección titulada «Aumento de la Seguridad»Para producción, reemplace Auth::auth() con una versión más robusta:
namespace Nibiru;use Nibiru\Pdo;
class HardenedAuth{ public function auth(string $login, string $password): bool { $row = Pdo::fetchRow( 'SELECT user_id, user_pass FROM "user" WHERE user_login = :l AND user_account_active = 1', [':l' => $login] ); if (!$row || !password_verify($password, $row['user_pass'])) { return false; } if (password_needs_rehash($row['user_pass'], PASSWORD_ARGON2ID)) { Pdo::update('user', [ 'user_pass' => password_hash($password, PASSWORD_ARGON2ID), ], ['user_id' => $row['user_id']]); } session_regenerate_id(true); $_SESSION['auth'] = [ 'session_id' => session_id(), 'user_id' => $row['user_id'], 'login' => $login, ]; return true; }}Migrar filas existentes en el primer inicio de sesión con password_needs_rehash.
Nibiru no genera tokens CSRF automáticamente. Añádelos tú mismo:
public function pageAction() { if (!isset($_SESSION['csrf'])) { $_SESSION['csrf'] = bin2hex(random_bytes(16)); } View::assign(['csrf' => $_SESSION['csrf']]);}
public function submitAction() { if (!hash_equals($_SESSION['csrf'] ?? '', $_POST['csrf'] ?? '')) { http_response_code(419); return; } / ...handle submission...}Incorpore <input type="hidden" name="csrf" value="{$csrf}"> en su formulario.
Inicio de sesión con código QR (patrón TPMS)
Sección titulada «Inicio de sesión con código QR (patrón TPMS)»Las aplicaciones de producción incluyen un inicio de sesión basado en código QR con enlace mágico que emite tokens de corta duración. El flujo:
- El usuario escanea el código QR → La URL es
/login/token/<one-time-token>. tokenActionvalida y crea una sesión.
El marco ya depende de bacon/bacon-qr-code y picqer/php-barcode-generator a través de Composer, por lo que puedes representar códigos QR en línea:
$writer = new \BaconQrCode\Writer(new \BaconQrCode\Renderer\ImageRenderer( new \BaconQrCode\Renderer\RendererStyle\RendererStyle(220), new \BaconQrCode\Renderer\Image\SvgImageBackEnd()));$svg = $writer->writeString('https://app.example.com/login/token/' . $token);View::assign(['qr' => $svg]);Trucos comunes
Sección titulada «Trucos comunes»$_SESSIONes reemplazado, no fusionado por el predeterminadoAuth::auth(). Cualquier cosa que hayas almacenado antes del inicio de sesión se pierde. Guarda y restaura explícitamente si es necesario.- No hay límite de velocidad. Agrega Fail2Ban o un observador estilo middleware.
- Las cookies de sesión necesitan banderas. Establece
session.cookie_secure = 1,session.cookie_httponly = 1ysession.cookie_samesite = "Lax"en php.ini para producción.