Forzar URLs https en Laravel

Estos últimos meses he estado inmerso en la integración de un portal usando el framework Laravel. Sus ventajas son muchas, sobre todo el tener una estructura de archivos muy sencilla y comprensible. Además, realizar cualquier función compleja es más sencillo gracias a sus rutas y filtros de urls.

Desde Laravel, las URLs se gestionan desde un único archivo, llamado routes.php, que nos permite indicar a cada URL qué página tiene que cargar. Por supuesto, podemos generar URLs dinámicas y amigables mediante variables.

Cómo funcionan las URLs en Laravel:

Desde este archivo de app/routes.php podemos generar vistas como la siguiente:

// Esta regla indica que al ir a la página de inicio debe cargar la plantilla "home"
Route::get('/', function()
{
  return View::make('home');
});

// Esta otra regla nos indicaría que al escribir http://miweb.com/servicios/ cargara la plantilla "services"
Route::get('servicios', function()
{
    return View::make('services');
});

Las plantillas las veremos en otro artículo. Simplemente decir que cada una representa un archivo HTML con la información y estructura deseada.

URLs avanzadas

Las URLs de Laravel nos permiten mucho más que cargar una simple plantilla HTML. También pueden hacer redirecciones, pasar variables a una plantilla o directamente cargar una función, que estará definida dentro de un controlador. Estos son los ejemplos:

// Antes de cargar la plantilla de usuarios, hacemos una consulta a la base de datos y enviamos el listado
// como una variable "$users" a la plantilla. Podemos añadir tantos "->with" como necesitemos.
Route::get('users', function()
{
    $users = User::all();
    return View::make('users')->with('users', $users);
});

// Si tenemos una página que ya no queremos pero no deseamos que la URL lleve a una página vacía o error,
// podemos hacer que rediriga hacia una 404 propia.
Route::get('url-borrada', function()
{
    return Redirect::to('/pagina-no-encontrada/');  
});

// Si tenemos un buscador, podríamos procesar la búsqueda antes de mostrar la pantalla de resultados,
// donde cogeríamos la variable dinámica de la URL mediante $variable, que se cargaría en el controlador.
// El controlador es un archivo llamado customController.php, en este caso, y cargaría la función "buscar".
Route::get('/buscar/{variable}', array(
  'uses' => 'customController@buscar')
);

Forzar URLs https en Laravel

Vamos a hablar de lo importante del artículo. Ahora que ya conocemos un poco más el funcionamiento de las URLs en Laravel, ¿cómo podemos forzar que una página cargue en http o en https? La solución no es sencilla. Tras buscar en muchos foros vi que daban muy pocas opciones. La primera es usando una función del propio Laravel:

// Comprueba si la página "foo" se ha cargado bajo el protocolo HTTPS
Route::get('foo', array('https', function()
{
    return 'Must be over HTTPS';
}));

Aunque esta opción no nos sirve. Lo único que hace es diferenciar la ruta entre el http y el https y si entramos por el segundo nos puede ofrecer otra página o plantilla. Lo que realmente queremos es que si entro por https, me redirija a http, si es lo que yo quiero. O al revés, según las necesidades.

Para poder hacerlo, usaremos los filtros. Son funciones que se cargan antes que las rutas. Sería el primer proceso nada más solicitar una URL al servidor. Los filtros están en routes.php. Desde aquí podemos crear dos filtros, uno que fuerce la página a cargarse en http y otro que fuerce a html.

Desde la página de app/routes.php, añadiríamos estas funciones al final:

// Forzar el https. Comprueba si la ruta actual NO es https y en ese caso lo redirecciona a HTTPS
Route::filter('forcehttps', function()
{
  if(!Request::secure())
  {
    return Redirect::secure(Request::getRequestUri(),301);
  }
});

// Forzar el http. Comprueba si la ruta actual ES https y en ese caso lo redirecciona a HTTP
Route::filter('forcehttp', function()
{
  $url = Request::url();
  if(Request::secure()){
    $url = str_replace('https://','http://',$url);
    return Redirect::to($url,301);
  }
});

¿Y cómo actualizamos las rutas para que usen los filtros? De la siguiente forma, dentro del routes.php:

// Si intentamos entrar en la home por https, el filtro lo redireccionará a http
Route::get('/', array('before'=>'forcehttp', function()
{
    return View::make('home');
}));

// Si intentamos entrar en la página de login, por ejemplo, por http, el filtro lo redireccionará a https
Route::get('/login/', array(
  'before'=>'forcehttps',
  'uses' => 'userController@login')
);

Espero que esta solución os haya servido igual que a mi. A nivel de rendimiento no se si es la mejor opción, pero haciendo pruebas no he notado ninguna sobrecarga en el servidor. Si alguien conoce una forma mejor de redireccionar, sin usar .htaccess, que comente.

Documentación oficial sobre rutas en Laravel

Forzar URLs https en Laravel

Blog, PHP |