A continuación montaremos un sistema de recuperación de contraseñas basado en Laravel 4.2
Generamos el archivo migration para la tabla reminder
php artisan auth:reminders-table
Podríamos generar el controlador vía consola
php artisan auth:reminders-controller
Pero en nuestro caso y dado que partimos de un ejemplo algo personalizado y podría variar alguna de las líneas, sustituiremos el código generado por el siguiente:
<?php
class RemindersController extends Controller {
/**
* Display the password reminder view.
*
* @return Response
*/
public function getRemind()
{
return View::make('password-reset.remind');
}
/**
* Handle a POST request to remind a user of their password.
*
* @return Response
*/
public function postRemind()
{
switch ($response = Password::remind(Input::only('email')))
{
case Password::INVALID_USER:
return Redirect::back()->with('error', Lang::get($response));
case Password::REMINDER_SENT:
return Redirect::back()->with('status', Lang::get($response));
}
}
/**
* Display the password reset view for the given token.
*
* @param string $token
* @return Response
*/
public function getReset($token = null)
{
if (is_null($token)) App::abort(404);
return View::make('password-reset.reset')->with('token', $token);
}
/**
* Handle a POST request to reset a user's password.
*
* @return Response
*/
public function postReset()
{
$credentials = Input::only(
'email', 'password', 'password_confirmation', 'token'
);
$response = Password::reset($credentials, function($user, $password)
{
$user->password = Hash::make($password);
$user->save();
});
switch ($response)
{
case Password::INVALID_PASSWORD:
case Password::INVALID_TOKEN:
case Password::INVALID_USER:
return Redirect::back()->with('error', Lang::get($response));
case Password::PASSWORD_RESET:
return Redirect::to('/access?email=' . Input::get('email'))->with('password_changed', 1);
}
}
}
En el archivo roots pegaremos las siguientes rutas
Route::get('password-reset', 'RemindersController@getRemind');
Route::post('password-modify', 'RemindersController@postRemind');
Route::get('password/reset/{token}', 'RemindersController@getReset');
Route::post('password/reset', 'RemindersController@postReset');
Podemos modificar el template de email que viene por defecto en /views/emails/auth por el siguiente:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="es">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="format-detection" content="telephone=no">
<title>Mondelez</title>
<style>
.container {
width: 600px;
max-width: 600px;
}
.container-padding {
padding-left: 24px;
padding-right: 24px;
}
.content {
padding-top: 22px;
padding-bottom: 22px;
background-color: #ffffff;
}
.col {
font-family: Helvetica, Arial, sans-serif;
font-size: 14px;
line-height: 20px;
text-align: left;
color: #333333;
width: 100%;
}
body {
margin: 0;
padding: 0;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
table {
border-spacing: 0;
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
}
table td {
border-collapse: collapse;
}
img {
-ms-interpolation-mode: bicubic;
}
@media screen and (max-width: 599px) {
.force-row,
.container {
width: 100% !important;
max-width: 100% !important;
}
}
@media screen and (max-width: 400px) {
.container-padding {
padding-left: 12px !important;
padding-right: 12px !important;
}
}
</style>
</head>
<body style="margin:0; padding:0;" bgcolor="#FFFFFF" leftmargin="0" topmargin="0" marginwidth="0" marginheight="0">
<table border="0" width="100%" height="100%" cellpadding="20" cellspacing="0" bgcolor="#FFFFFF">
<tr>
<td align="center" valign="top" bgcolor="#FFFFFF" style="background-color: #FFFFFF;">
<table cellpadding="0" cellspacing="0" border="0" width="600" class="container">
<tr>
<td align="center"><img src="{{ URL::to('assets/images/logo.png') }}" width="76" height="76" /></td>
</tr>
<tr>
<td height="42"></td>
</tr>
<tr>
<td align="center">
<table cellpadding="0" cellspacing="0" border="0" align="center" style="width: 100%; max-width: 400px;">
<tr>
<td align="center">
<h3 style="font-family: Arial, Gotham, 'Helvetica Neue', Helvetica, sans-serif; color:#333; font-size:16px; margin-bottom: 20px; padding-bottom: 0;">Cambio de contraseña</h3>
<p style="font-family: Arial, Gotham, 'Helvetica Neue', Helvetica, sans-serif; color:#333; font-size:14px; padding-bottom: 30px;">Para cambiar tu contraseña haz clic en el siguiente botón y rellena el formulario.</p>
<p style="font-family: Arial, Gotham, 'Helvetica Neue', Helvetica, sans-serif; color:#333; font-size:14px; padding-bottom: 30px;">El enlace caducará en {{ Config::get('auth.reminder.expire', 60) }} minutos.</p>
<table cellpadding="0" cellspacing="0" border="0" bgcolor="#000000">
<tr>
<td style="color:#FFF; padding:9px; font-size:14px; font-family: Arial, Helvetica, sans-serif;">
<a style="text-decoration:none; color:#FFFFFF;" href="{{ URL::to('password/reset', array($token)) }}" target="_blank">CLICA AQUÍ</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td height="45"></td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
Y solo nos quedará crear las vistas de la pantalla donde pediremos el correo electrónico y donde confirmaremos el correo y la nueva contraseña. Cabe destacar que estas dos pantallas están basadas en el theme del admin Milton.
Archivo remind.blade.php (petición del correo electrónico)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="author" content="4funkies">
<link rel="shortcut icon" href="assets/images/favicon_1.ico">
<title>SmartPlace by Mondel?z</title>
{{ HTML::style("assets/css/bootstrap.min.css") }}
{{ HTML::style("assets/css/core.css") }}
{{ HTML::style("assets/css/icons.css") }}
{{ HTML::style("assets/css/components.css") }}
{{ HTML::style("assets/css/pages.css") }}
{{ HTML::style("assets/css/menu.css") }}
{{ HTML::style("assets/css/responsive.css") }}
{{ HTML::script("assets/js/modernizr.min.js") }}
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
{{ HTML::script("https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js") }}
{{ HTML::script("https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js") }}
<![endif]-->
</head>
<body>
<div class="wrapper-page">
<div class="text-center">
<a href="/" class="logo-lg">
<i class="md md-directions-car"></i>
<span>SmartPlace by Mondel?z</span>
</a>
</div>
<div class="row">
<div class="col-sm-12">
<h4 class="page-title">¿Olvidaste tu contraseña?</h4>
<p>Introduce tu correo electrónico y te enviaremos un enlace para crear una nueva.</p>
</div>
</div>
{{ Form::open(array('url' => action('RemindersController@postRemind'))) }}
<div class="form-group m-t-15">
<div class="input-group">
{{ Form::text('email', '', array('class'=>'form-control', 'placeholder' => 'Correo electrónico', 'required')) }}
<i class="md md-email form-control-feedback l-h-34" style="left:6px;"></i>
<span class="input-group-btn"> <button type="submit" class="btn btn-email btn-primary waves-effect waves-light">Enviar</button> </span>
</div>
</div>
{{ Form::close() }}
@if( Session::get('error') )
<div class="alert alert-danger alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
{{ Session::get('error') }}
</div>
@endif
@if( Session::get('status') )
<div class="alert alert-success alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
{{ Session::get('status') }}
</div>
@endif
</div>
<script>
var resizefunc = [];
</script>
<!-- Main -->
{{ HTML::script("assets/js/jquery.min.js") }}
{{ HTML::script("assets/js/bootstrap.min.js") }}
{{ HTML::script("assets/js/detect.js") }}
{{ HTML::script("assets/js/fastclick.js") }}
{{ HTML::script("assets/js/jquery.slimscroll.js") }}
{{ HTML::script("assets/js/jquery.blockUI.js") }}
{{ HTML::script("assets/js/waves.js") }}
{{ HTML::script("assets/js/wow.min.js") }}
{{ HTML::script("assets/js/jquery.nicescroll.js") }}
{{ HTML::script("assets/js/jquery.scrollTo.min.js") }}
<!-- Custom main Js -->
{{ HTML::script("assets/js/jquery.core.js") }}
{{ HTML::script("assets/js/jquery.app.js") }}
</body>
</html>
Archivo reset.blade.php (confirmación email y nueva contraseña)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="author" content="4funkies">
<link rel="shortcut icon" href="assets/images/favicon_1.ico">
<title>SmartPlace by Mondel?z</title>
{{ HTML::style("assets/css/bootstrap.min.css") }}
{{ HTML::style("assets/css/core.css") }}
{{ HTML::style("assets/css/icons.css") }}
{{ HTML::style("assets/css/components.css") }}
{{ HTML::style("assets/css/pages.css") }}
{{ HTML::style("assets/css/menu.css") }}
{{ HTML::style("assets/css/responsive.css") }}
{{ HTML::script("assets/js/modernizr.min.js") }}
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
{{ HTML::script("https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js") }}
{{ HTML::script("https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js") }}
<![endif]-->
</head>
<body>
<div class="wrapper-page">
<div class="text-center">
<a href="/" class="logo-lg">
<i class="md md-directions-car"></i>
<span>SmartPlace by Mondel?z</span>
</a>
</div>
<div class="row">
<div class="col-sm-12">
<h4 class="page-title">Cambio de contraseña</h4>
<p>Introduce tu correo electrónico y una nueva contraseña de acceso</p>
</div>
</div>
{{ Form::open(array('url' => action('RemindersController@postReset'))) }}
<div class="form-group m-t-15">
<div class="input-group">
{{ Form::email('email', Input::old('email'), array('class' => 'form-control', 'placeholder' => 'Correo electrónico', 'parsley-type' => "email", 'required')) }}
<span class="input-group-addon">
<i class="fa fa-envelope-o"></i>
</span>
</div>
</div>
<div class="form-group">
<div class="input-group">
{{ Form::password('password', array('class' => 'form-control', 'placeholder' => 'Contraseña', 'id' => "pass", 'required')) }}
<span class="input-group-addon">
<i class="fa fa-key"></i>
</span>
</div>
</div>
<div class="form-group">
<div class="input-group">
{{ Form::password('password_confirmation', array('class' => 'form-control', 'placeholder' => 'Repetir contraseña', 'data-parsley-equalto' => "#pass", 'required')) }}
<span class="input-group-addon">
<i class="fa fa-key"></i>
</span>
</div>
</div>
<div class="form-group">
{{ Form::submit('Enviar', array('class' => 'btn btn-primary m-t-15')) }}
</div>
{{ Form::hidden('token', $token) }}
{{ Form::close() }}
@if( Session::get('error') )
<div class="alert alert-danger alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
{{ Session::get('error') }}
</div>
@endif
</div>
<script>
var resizefunc = [];
</script>
<!-- Main -->
{{ HTML::script("assets/js/jquery.min.js") }}
{{ HTML::script("assets/js/bootstrap.min.js") }}
{{ HTML::script("assets/js/detect.js") }}
{{ HTML::script("assets/js/fastclick.js") }}
{{ HTML::script("assets/js/jquery.slimscroll.js") }}
{{ HTML::script("assets/js/jquery.blockUI.js") }}
{{ HTML::script("assets/js/waves.js") }}
{{ HTML::script("assets/js/wow.min.js") }}
{{ HTML::script("assets/js/jquery.nicescroll.js") }}
{{ HTML::script("assets/js/jquery.scrollTo.min.js") }}
{{ HTML::script('assets/plugins/parsleyjs/dist/parsley.min.js') }}
<!-- Custom main Js -->
{{ HTML::script("assets/js/jquery.core.js") }}
{{ HTML::script("assets/js/jquery.app.js") }}
<script type="text/javascript">
$(document).ready(function() {
$('form').parsley();
});
</script>
</body>
</html>

