7: Iniciar Sesión
7: Iniciar Sesión
1. Introducción
En este tutorial implementaremos el sistema de inicio de sesión para nuestra aplicación. Crearemos una vista personalizada de login, configuraremos las rutas y redirecciones, y prepararemos el dashboard principal que verán los usuarios después de autenticarse.
2. Objetivos
✅ Crear vista personalizada de inicio de sesión
✅ Configurar el formulario de login con CSRF
✅ Crear el controlador y modelo de inicio
✅ Configurar redirecciones después del login
✅ Implementar validación de autenticación en el layout
3. Configuración de Rutas
Paso 1: Modificar routes/web.php
Actualizamos el archivo de rutas para incluir la nueva ruta de inicio:
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\HomeController;
use App\Http\Controllers\InicioController;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
*/
// Ruta principal: mostrar selección de roles
Route::get('/', function () {
return view('modulos.seleccionar');
});
// Ruta para el login personalizado
Route::get('/ingresar', function () {
return view('modulos.ingresar');
});
// Rutas de autenticación de Laravel
Auth::routes();
// Dashboard (protegido por autenticación)
Route::get('/home', [HomeController::class, 'index'])->name('home');
// Ruta de inicio después del login
Route::get('/inicio', [InicioController::class, 'index'])->name('inicio');4. Crear la Vista de Login Personalizada
Paso 1: Crear ingresar.blade.php
Crea el archivo resources/views/modulos/ingresar.blade.php:
@extends('layouts.app')
@section('title', 'Iniciar Sesión')
@section('content')
<div class="login-page">
<div class="login-box">
<!-- Logo -->
<div class="login-logo">
<a href="#"><b>Clínica</b> Médica</a>
</div>
<!-- /.login-logo -->
<div class="login-box-body">
<p class="login-box-msg">Ingresar al sistema</p>
<!-- Formulario de Login -->
<form method="POST" action="{{ route('login') }}">
@csrf
<!-- Campo: Email -->
<div class="form-group has-feedback">
<input type="email"
name="email"
class="form-control"
placeholder="Correo electrónico"
value="{{ old('email') }}"
required autofocus>
<span class="glyphicon glyphicon-envelope form-control-feedback"></span>
@error('email')
<span class="help-block text-danger">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
<!-- Campo: Password -->
<div class="form-group has-feedback">
<input type="password"
name="password"
class="form-control"
placeholder="Contraseña"
required>
<span class="glyphicon glyphicon-lock form-control-feedback"></span>
@error('password')
<span class="help-block text-danger">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
<!-- Opciones: Recordar y Olvidé contraseña -->
<div class="row">
<div class="col-xs-8">
<div class="checkbox icheck">
<label>
<input type="checkbox" name="remember" {{ old('remember') ? 'checked' : '' }}>
Recordarme
</label>
</div>
</div>
<!-- /.col -->
<div class="col-xs-4">
<button type="submit" class="btn btn-primary btn-block btn-flat">
<i class="fa fa-sign-in"></i> Ingresar
</button>
</div>
<!-- /.col -->
</div>
</form>
<!-- Enlaces adicionales -->
<div class="social-auth-links text-center">
<p>- O -</p>
<a href="{{ route('register') }}" class="btn btn-block btn-success btn-flat">
<i class="fa fa-user-plus"></i> Registrarse como nuevo usuario
</a>
</div>
<!-- /.social-auth-links -->
<a href="{{ url('/') }}" class="text-center">
<i class="fa fa-arrow-left"></i> Volver a seleccionar
</a>
</div>
<!-- /.login-box-body -->
</div>
<!-- /.login-box -->
</div>
<!-- /.login-page -->
@endsection
@push('styles')
<style>
.login-page {
background: #3c8dbc;
background: -webkit-linear-gradient(to right, #3c8dbc, #2c3e50);
background: linear-gradient(to right, #3c8dbc, #2c3e50);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.login-box {
width: 400px;
margin: 0 auto;
}
.login-box-body {
background: #ffffff;
padding: 20px;
border-top: 0;
color: #666;
border-radius: 4px;
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
}
.login-logo a {
color: #fff;
font-size: 35px;
font-weight: 300;
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
}
.login-logo a b {
font-weight: 700;
}
.login-box-msg {
margin: 0;
text-align: center;
padding: 0 0 20px 0;
font-size: 18px;
border-bottom: 1px solid #f4f4f4;
color: #444;
}
.has-feedback .form-control-feedback {
top: 0;
right: 0;
color: #777;
line-height: 34px;
}
.help-block.text-danger {
color: #dd4b39;
margin-top: 5px;
}
.icheck > label {
padding-left: 0;
font-weight: normal;
}
.social-auth-links {
margin: 15px 0 10px 0;
}
.btn-flat {
border-radius: 0;
}
</style>
@endpush5. Crear el Controlador de Inicio
Paso 1: Generar el controlador y modelo
Ejecuta el siguiente comando para crear el controlador y modelo juntos:
php artisan make:model Inicio -c -rExplicación del comando:
make:model Inicio→ Crea el modeloInicio-c→ Crea el controlador junto con el modelo-r→ Crea el controlador con métodos de recurso (index, create, store, etc.)
Paso 2: El controlador generado
Se generará app/Http/Controllers/InicioController.php:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class InicioController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
// Vista de inicio después del login
return view('modulos.inicio');
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
}
}6. Crear la Vista de Inicio
Paso 1: Crear inicio.blade.php
Crea el archivo resources/views/modulos/inicio.blade.php:
@extends('layouts.app')
@section('title', 'Inicio')
@section('page-title', 'Panel de Control')
@section('page-subtitle', 'Bienvenido al sistema')
@section('breadcrumb')
<li class="active">Inicio</li>
@endsection
@section('content')
<div class="row">
<div class="col-md-12">
<div class="box box-primary">
<div class="box-header with-border">
<h3 class="box-title">
<i class="fa fa-dashboard"></i> Bienvenido al sistema
</h3>
<div class="box-tools pull-right">
<button type="button" class="btn btn-box-tool" data-widget="collapse">
<i class="fa fa-minus"></i>
</button>
</div>
</div>
<!-- /.box-header -->
<div class="box-body">
<div class="row">
<div class="col-md-4 col-sm-6 col-xs-12">
<div class="info-box">
<span class="info-box-icon bg-aqua"><i class="fa fa-user-md"></i></span>
<div class="info-box-content">
<span class="info-box-text">Doctores</span>
<span class="info-box-number">5</span>
</div>
<!-- /.info-box-content -->
</div>
<!-- /.info-box -->
</div>
<!-- /.col -->
<div class="col-md-4 col-sm-6 col-xs-12">
<div class="info-box">
<span class="info-box-icon bg-green"><i class="fa fa-users"></i></span>
<div class="info-box-content">
<span class="info-box-text">Pacientes</span>
<span class="info-box-number">12</span>
</div>
<!-- /.info-box-content -->
</div>
<!-- /.info-box -->
</div>
<!-- /.col -->
<div class="col-md-4 col-sm-6 col-xs-12">
<div class="info-box">
<span class="info-box-icon bg-yellow"><i class="fa fa-calendar"></i></span>
<div class="info-box-content">
<span class="info-box-text">Citas Hoy</span>
<span class="info-box-number">3</span>
</div>
<!-- /.info-box-content -->
</div>
<!-- /.info-box -->
</div>
<!-- /.col -->
</div>
<!-- /.row -->
<div class="row">
<div class="col-md-6">
<div class="box box-success">
<div class="box-header with-border">
<h3 class="box-title">
<i class="fa fa-clock-o"></i> Actividad Reciente
</h3>
</div>
<div class="box-body">
<ul class="todo-list">
<li>
<span class="text">
Bienvenido <strong>{{ Auth::user()->name }}</strong> al sistema de citas médicas
</span>
<small class="label label-info pull-right">
<i class="fa fa-clock-o"></i> Ahora
</small>
</li>
<li>
<span class="text">
Tu rol en el sistema es: <strong>{{ Auth::user()->rol }}</strong>
</span>
<small class="label label-success pull-right">
<i class="fa fa-check"></i> Activo
</small>
</li>
</ul>
</div>
</div>
</div>
<div class="col-md-6">
<div class="box box-warning">
<div class="box-header with-border">
<h3 class="box-title">
<i class="fa fa-info-circle"></i> Información del Usuario
</h3>
</div>
<div class="box-body">
<table class="table table-striped">
<tr>
<th><i class="fa fa-user"></i> Nombre:</th>
<td>{{ Auth::user()->name }}</td>
</tr>
<tr>
<th><i class="fa fa-envelope"></i> Email:</th>
<td>{{ Auth::user()->email }}</td>
</tr>
<tr>
<th><i class="fa fa-id-card"></i> Documento:</th>
<td>{{ Auth::user()->documento ?? 'No registrado' }}</td>
</tr>
<tr>
<th><i class="fa fa-phone"></i> Teléfono:</th>
<td>{{ Auth::user()->telefono ?? 'No registrado' }}</td>
</tr>
<tr>
<th><i class="fa fa-tag"></i> Rol:</th>
<td>
<span class="label label-primary">{{ Auth::user()->rol }}</span>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- /.box-body -->
</div>
<!-- /.box -->
</div>
</div>
@endsection
@push('styles')
<style>
.info-box {
min-height: 90px;
background: #fff;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
border-radius: 4px;
transition: all 0.3s ease;
}
.info-box:hover {
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(0,0,0,0.15);
}
.info-box-icon {
border-radius: 4px 0 0 4px;
display: block;
float: left;
height: 90px;
width: 90px;
text-align: center;
font-size: 45px;
line-height: 90px;
background: rgba(0,0,0,0.2);
}
.info-box-content {
padding: 5px 10px;
margin-left: 90px;
}
.info-box-number {
display: block;
font-weight: 700;
font-size: 28px;
color: #333;
}
.info-box-text {
display: block;
font-size: 14px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
text-transform: uppercase;
color: #888;
}
.todo-list {
margin: 0;
padding: 0;
list-style: none;
}
.todo-list > li {
border-radius: 2px;
padding: 10px 15px;
background: #f4f4f4;
margin-bottom: 2px;
border-left: 2px solid #e6e7e8;
color: #444;
position: relative;
}
.todo-list > li .text {
display: inline-block;
font-weight: 600;
}
.todo-list > li .label {
margin-left: 10px;
font-size: 11px;
padding: 3px 8px;
}
.table td, .table th {
padding: 8px 12px;
vertical-align: middle;
}
</style>
@endpush7. Modificar el Layout para Autenticación
Paso 1: Actualizar layouts/app.blade.php
Modificamos el layout para mostrar contenido diferente según si el usuario está autenticado:
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>@yield('title', 'Clínica L8') - Sistema de Citas Médicas</title>
<!-- Google Font: Source Sans Pro -->
<link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700" rel="stylesheet">
<!-- AdminLTE CSS -->
<link rel="stylesheet" href="{{ asset('bower_components/bootstrap/dist/css/bootstrap.min.css') }}">
<link rel="stylesheet" href="{{ asset('bower_components/font-awesome/css/font-awesome.min.css') }}">
<link rel="stylesheet" href="{{ asset('bower_components/Ionicons/css/ionicons.min.css') }}">
<link rel="stylesheet" href="{{ asset('dist/css/AdminLTE.min.css') }}">
<link rel="stylesheet" href="{{ asset('dist/css/skins/_all-skins.min.css') }}">
@stack('styles')
</head>
<body class="hold-transition skin-blue {{ Auth::check() ? 'sidebar-mini' : '' }}">
@auth
<!-- ========================================== -->
<!-- LAYOUT CON AUTENTICACIÓN -->
<!-- ========================================== -->
<div class="wrapper">
<!-- Header -->
<header class="main-header">
<a href="{{ url('/inicio') }}" class="logo">
<span class="logo-mini"><b>C</b>L</span>
<span class="logo-lg"><b>Clínica</b> L8</span>
</a>
<nav class="navbar navbar-static-top">
<a href="#" class="sidebar-toggle" data-toggle="push-menu" role="button">
<span class="sr-only">Toggle navigation</span>
</a>
<div class="navbar-custom-menu">
<ul class="nav navbar-nav">
<li class="dropdown user user-menu">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<img src="{{ asset('dist/img/user2-160x160.jpg') }}" class="user-image" alt="User Image">
<span class="hidden-xs">{{ Auth::user()->name }}</span>
</a>
<ul class="dropdown-menu">
<li class="user-header">
<img src="{{ asset('dist/img/user2-160x160.jpg') }}" class="img-circle" alt="User Image">
<p>
{{ Auth::user()->name }}
<small>{{ Auth::user()->rol }}</small>
</p>
</li>
<li class="user-footer">
<div class="pull-left">
<a href="#" class="btn btn-default btn-flat">Perfil</a>
</div>
<div class="pull-right">
<a href="{{ route('logout') }}" class="btn btn-default btn-flat"
onclick="event.preventDefault(); document.getElementById('logout-form').submit();">
Cerrar Sesión
</a>
<form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
@csrf
</form>
</div>
</li>
</ul>
</li>
</ul>
</div>
</nav>
</header>
<!-- Sidebar -->
<aside class="main-sidebar">
<section class="sidebar">
<!-- User Panel -->
<div class="user-panel">
<div class="pull-left image">
<img src="{{ asset('dist/img/user2-160x160.jpg') }}" class="img-circle" alt="User Image">
</div>
<div class="pull-left info">
<p>{{ Auth::user()->name }}</p>
<a href="#"><i class="fa fa-circle text-success"></i> Online</a>
</div>
</div>
<!-- Menu -->
<ul class="sidebar-menu" data-widget="tree">
<li class="header">MENÚ PRINCIPAL</li>
<li class="{{ request()->routeIs('inicio') ? 'active' : '' }}">
<a href="{{ route('inicio') }}">
<i class="fa fa-dashboard"></i> <span>Dashboard</span>
</a>
</li>
@if(Auth::user()->rol == 'admin')
<li class="header">ADMINISTRACIÓN</li>
<li>
<a href="#">
<i class="fa fa-cogs"></i> <span>Configuración</span>
</a>
</li>
@endif
@if(in_array(Auth::user()->rol, ['admin', 'secretaria']))
<li class="header">GESTIÓN</li>
<li>
<a href="#">
<i class="fa fa-building"></i> <span>Consultorios</span>
</a>
</li>
<li>
<a href="#">
<i class="fa fa-user-md"></i> <span>Doctores</span>
</a>
</li>
<li>
<a href="#">
<i class="fa fa-users"></i> <span>Pacientes</span>
</a>
</li>
@endif
</ul>
</section>
</aside>
<!-- Content Wrapper -->
<div class="content-wrapper">
<!-- Content Header -->
<section class="content-header">
<h1>
@yield('page-title', 'Dashboard')
<small>@yield('page-subtitle', 'Panel de control')</small>
</h1>
<ol class="breadcrumb">
<li><a href="{{ route('inicio') }}"><i class="fa fa-dashboard"></i> Inicio</a></li>
@yield('breadcrumb')
</ol>
</section>
<!-- Main Content -->
<section class="content">
@yield('content')
</section>
</div>
<!-- Footer -->
<footer class="main-footer">
<div class="pull-right hidden-xs">
<b>Versión</b> 1.0.0
</div>
<strong>Copyright © 2024 <a href="#">Clínica L8</a>.</strong> Todos los derechos reservados.
</footer>
</div>
@else
<!-- ========================================== -->
<!-- LAYOUT SIN AUTENTICACIÓN -->
<!-- ========================================== -->
@yield('content')
@endauth
<!-- Scripts -->
<script src="{{ asset('bower_components/jquery/dist/jquery.min.js') }}"></script>
<script src="{{ asset('bower_components/bootstrap/dist/js/bootstrap.min.js') }}"></script>
<script src="{{ asset('dist/js/adminlte.min.js') }}"></script>
@stack('scripts')
</body>
</html>8. Modificar el LoginController para Redirección
Paso 1: Actualizar app/Http/Controllers/Auth/LoginController.php
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller
{
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* @var string
*/
protected $redirectTo = '/inicio';
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
}
}9. Verificar el Sistema
Paso 1: Iniciar sesión
Ve a
http://127.0.0.1:8000Haz clic en cualquier tarjeta (ej: Secretaria)
Serás redirigido a la página de login
Ingresa tus credenciales:
Email: maria@example.com
Password: 123
Paso 2: Verificar el dashboard
Después del login, deberías ver el dashboard personalizado:
┌─────────────────────────────────────────────────────────────────┐
│ [C] Clínica L8 👤 María [▼] [Cerrar] │
├─────────────────────────────────────────────────────────────────┤
│ ☰ Dashboard │
│ MENÚ PRINCIPAL │
│ Dashboard │
│ ADMINISTRACIÓN │
│ Configuración │
│ GESTIÓN │
│ Consultorios │
│ Doctores │
│ Pacientes │
├─────────────────────────────────────────────────────────────────┤
│ Dashboard / Panel de control │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 👨⚕️ │ │ 👥 │ │ 📅 │ │
│ │ Doctores │ │ Pacientes │ │ Citas Hoy │ │
│ │ 5 │ │ 12 │ │ 3 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ ┌──────────────────────────┐ ┌──────────────────────────┐ │
│ │ 🕐 Actividad Reciente │ │ ℹ️ Información Usuario │ │
│ │ Bienvenido María ... │ │ Nombre: María Gaspard │ │
│ │ Rol: admin │ │ Email: maria@... │ │
│ └──────────────────────────┘ └──────────────────────────┘ │
│ │
│ Copyright © 2024 Clínica L8. │
└─────────────────────────────────────────────────────────────────┘10. Resumen de Archivos Creados/Modificados
| Archivo | Acción |
|---|---|
routes/web.php | Modificado (nuevas rutas) |
resources/views/modulos/ingresar.blade.php | Crear (login personalizado) |
resources/views/modulos/inicio.blade.php | Crear (dashboard) |
resources/views/layouts/app.blade.php | Modificado (autenticación condicional) |
app/Http/Controllers/InicioController.php | Crear (controlador) |
app/Http/Controllers/Auth/LoginController.php | Modificado (redirección) |
app/Models/Inicio.php | Crear (modelo, no usado aún) |
11. Comandos Útiles
# Crear controlador con modelo
php artisan make:model Inicio -c -r
# Limpiar caché de vistas
php artisan view:clear
# Limpiar caché de rutas
php artisan route:clear
# Ver rutas registradas
php artisan route:list12. Solución de Problemas
| Problema | Solución |
|---|---|
Route [login] not defined | Ejecuta php artisan route:clear |
| Error 404 después del login | Verifica que la ruta /inicio esté registrada |
| No se ve el dashboard | Verifica que InicioController::index exista |
| CSRF token mismatch | Asegura @csrf en el formulario |
| Redirección a /home | Cambia $redirectTo en LoginController |
13. Conclusión
🎉 ¡Excelente trabajo! Hemos implementado:
✅ Sistema de login personalizado con diseño AdminLTE
✅ Dashboard de bienvenida con información del usuario
✅ Redirección correcta después de la autenticación
✅ Layout condicional (con/sin autenticación)
✅ Menú dinámico según el rol del usuario
En el próximo tutorial comenzaremos a desarrollar el módulo de secretaria, empezando con la gestión de consultorios (CRUD).
Comentarios
Publicar un comentario