Laravel 5 - redirection vers HTTPS

127

Je travaille sur mon premier projet Laravel 5 et je ne sais pas où ni comment placer la logique pour forcer HTTPS sur mon application. Le cliché ici est qu'il existe de nombreux domaines pointant vers l'application et que seuls deux sur trois utilisent SSL (le troisième est un domaine de secours, une longue histoire). Je voudrais donc gérer cela dans la logique de mon application plutôt que dans .htaccess.

Dans Laravel 4.2, j'ai effectué la redirection avec ce code, situé dans filters.php:

App::before(function($request)
{
    if( ! Request::secure())
    {
        return Redirect::secure(Request::path());
    }
});

Je pense que le middleware est l'endroit où quelque chose comme ça devrait être implémenté, mais je ne peux pas vraiment comprendre cela en l'utilisant.

Merci!

METTRE À JOUR

Si vous utilisez Cloudflare comme moi, ceci est accompli en ajoutant une nouvelle règle de page dans votre panneau de contrôle.

NuitMICU
la source
Alors, que se passe-t-il avec le 3e domaine? Si vous forcez https sur toutes les routes, le 3ème domaine continuera-t-il à fonctionner?
Laurence
Détecter cela avec$_SERVER['HTTP_HOST']
NightMICU
Combien de temps a-t-il fallu pour que la règle de page cloudflare entre en vigueur
CodeGuru
Oh, j'ai dû activer le proxy dans le réglage DNS haha!
CodeGuru

Réponses:

253

Vous pouvez le faire fonctionner avec une classe Middleware. Laissez-moi vous donner une idée.

namespace MyApp\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\App;

class HttpsProtocol {

    public function handle($request, Closure $next)
    {
            if (!$request->secure() && App::environment() === 'production') {
                return redirect()->secure($request->getRequestUri());
            }

            return $next($request); 
    }
}

Ensuite, appliquez ce middleware à chaque requête ajoutant la définition de la règle au Kernel.phpfichier, comme ceci:

protected $middleware = [
    'Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode',
    'Illuminate\Cookie\Middleware\EncryptCookies',
    'Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse',
    'Illuminate\Session\Middleware\StartSession',
    'Illuminate\View\Middleware\ShareErrorsFromSession',

    // appending custom middleware 
    'MyApp\Http\Middleware\HttpsProtocol'       

];

Dans l'exemple ci-dessus, le middleware redirigera chaque requête vers https si:

  1. La requête actuelle est livrée sans protocole sécurisé (http)
  2. Si votre environnement est égal à production. Alors, ajustez simplement les paramètres en fonction de vos préférences.

Cloudflare

J'utilise ce code dans un environnement de production avec un SSL WildCard et le code fonctionne correctement. Si je supprime&& App::environment() === 'production' et le teste dans localhost, la redirection fonctionne également. Donc, avoir ou non un SSL installé n'est pas le problème. Il semble que vous deviez porter une attention toute particulière à votre couche Cloudflare afin d'être redirigé vers le protocole Https.

Modifier 23/03/2015

Merci à @Adam Linkla suggestion de: cela est probablement causé par les en-têtes que Cloudflare passe. CloudFlare frappe probablement votre serveur via HTTP et transmet un en-tête X-Forwarded-Proto qui déclare qu'il transmet une requête HTTPS. Vous devez ajouter une autre ligne dans votre middleware qui dit ...

$request->setTrustedProxies( [ $request->getClientIp() ] ); 

... pour faire confiance aux en-têtes que CloudFlare envoie. Cela arrêtera la boucle de redirection

Edit 27/09/2016 - Laravel v5.3

Il suffit d'ajouter la classe middleware au webgroupe dans kernel.php file:

protected $middlewareGroups = [
    'web' => [
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,

        // here
        \MyApp\Http\Middleware\HttpsProtocol::class

    ],
];

N'oubliez pas que le webgroupe est appliqué à chaque route par défaut, vous n'avez donc pas besoin de le définir webexplicitement dans les routes ni les contrôleurs.

Edit 23/08/2018 - Laravel v5.7

  • Pour rediriger une demande en fonction de l'environnement que vous pouvez utiliser App::environment() === 'production'. Pour la version précédente était env('APP_ENV') === 'production' .
  • L'utilisation \URL::forceScheme('https');en fait ne redirige pas. Il crée simplement des liens avec https://une fois le site Web rendu.
manix
la source
5
Cela semble me donner une boucle de redirection ... on dirait que cela devrait fonctionner, cependant. Je ne sais pas si cela fait une différence mais nous utilisons un SSL Cloudflare. Mais je ne pense pas que cela changerait la simple redirection.
NightMICU
3
@NightMICU Je ne sais pas si vous avez résolu le problème de la redirection, mais il est probablement dû aux en-têtes transmis par Cloudflare. CloudFlare frappe probablement votre serveur via HTTP et transmet un en-tête X-Forwarded-Proto qui déclare qu'il transmet une requête HTTPS. Vous devez ajouter une autre ligne dans votre middleware qui indique de $request->setTrustedProxies( [ $request->getClientIp() ] );faire confiance aux en-têtes que CloudFlare envoie. Cela arrêtera la boucle de redirection.
Adam Link
2
@manix Génial. Je viens de passer par ce problème HTTPS ce week-end avec mon propre projet - ces petites choses vous frustreront pendant des heures!
Adam Link
8
Excellente réponse! Juste un détail: il est préférable d'utiliser une redirection 301 pour indiquer à Google qu'il s'agit d'un mouvement permanent. Comme:return redirect()->secure($request->getRequestUri(), 301);
adriaroca
4
pour ceux qui sous l'équilibreur de charge ou le proxy peuvent changer pour secure () à $request->server('HTTP_X_FORWARDED_PROTO') != 'https'cela fonctionne pour moi
Shiro
63

Une autre option qui a fonctionné pour moi, dans AppServiceProvider, placez ce code dans la méthode de démarrage:

\URL::forceScheme('https');

La fonction écrite avant forceSchema ('https') était fausse, son forceScheme

Constantin Stan
la source
16
Hé, je viens de trouver ça en cherchant sur Google - notez que dans la version 5.4 c'est\URL::forceScheme('https');
dev
5
Dans le même fichier, vous pouvez également faireif($this->app->environment() === 'production'){ $this->app['request']->server->set('HTTPS', true); }
Rory
2
did u mean\URL::forceScheme('https')
Ernest Okot
17
Je suis presque sûr que ce n'est que pour créer des liens. Cela ne forcera pas un utilisateur à https, il ne servira que les liens précédés de https: //
Weston Watson
ouais c'est arrivé @WestonWatson. veuillez partager la solution si elle est trouvée
Harat
33

Sinon, si vous utilisez Apache, vous pouvez utiliser un .htaccessfichier pour forcer vos URL à utiliser le httpspréfixe. Sur Laravel 5.4, j'ai ajouté les lignes suivantes à mon .htaccessfichier et cela a fonctionné pour moi.

RewriteEngine On

RewriteCond %{HTTPS} !on
RewriteRule ^.*$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Assad Ullah Ch
la source
2
Ce n'est pas bon si vous avez plusieurs environnements (développement, étape, production) que vous devez définir SSL sur chacun d'eux.
Mladen Janjetovic
@MladenJanjetovic, vous pouvez utiliser RewriteCond %{HTTP_HOST} !=localhostsur dev pour contourner ce problème .
Dan
3
@Dan - Oui, mais vous devrez toujours le configurer pour la scène, local (et c'est plus compliqué si les développeurs utilisent différentes URL dans le développement local, c'est-à-dire .dev, .local, sous-domaines, ... etc). Je préférerais avoir ce genre de logique dans l'application.
Mladen Janjetovic
16

pour laravel 5.4 utilisez ce format pour obtenir une redirection https au lieu de .htaccess

namespace App\Providers;

use Illuminate\Support\Facades\URL;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        URL::forceScheme('https');
    }
}
Arun Yokesh
la source
15
Juste pour clarifier: 1) ces modifications doivent être effectuées dans app / Providers / AppServiceProvider.php; 2) cela ne sert qu'à définir les liens générés dans l'application pour utiliser SSL, cela ne vous oblige pas à utiliser SSL
phoenix
Salut, Route ne génère pas par cette méthode si je clique sur un bouton qui m'envoie à la route suivante, cela ne me donne pas l'erreur 404
Saket Sinha
Ce n'est pas une redirection https. Mais cela permet la diffusion du site https: //. Si vous le changez en http: //, il servira également.
franc
12

Similaire à la réponse de manix mais en un seul endroit. Middleware pour forcer HTTPS

namespace App\Http\Middleware;

use Closure;

use Illuminate\Http\Request;

class ForceHttps
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request $request
     * @param  \Closure $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if (!app()->environment('local')) {
            // for Proxies
            Request::setTrustedProxies([$request->getClientIp()]);

            if (!$request->isSecure()) {
                return redirect()->secure($request->getRequestUri());
            }
        }

        return $next($request);
    }
}
Mladen Janjetovic
la source
La requête doit-elle être statique?
GFxJamal
@jRhesk ce n'est probablement pas le cas, mais essayez et n'hésitez pas à modifier la réponse
Mladen Janjetovic
8

Ceci est pour Larave 5.2.x et supérieur. Si vous souhaitez avoir la possibilité de diffuser du contenu via HTTPS et d'autres via HTTP, voici une solution qui a fonctionné pour moi. Vous vous demandez peut-être pourquoi quelqu'un voudrait-il diffuser uniquement du contenu via HTTPS? Pourquoi ne pas tout servir via HTTPS?

Bien qu'il soit tout à fait correct de desservir l'ensemble du site via HTTPS, tout interrompre via HTTPS entraîne une surcharge supplémentaire sur votre serveur. N'oubliez pas que le cryptage n'est pas bon marché. La légère surcharge a également un impact sur le temps de réponse de votre application. Vous pourriez soutenir que le matériel de base est bon marché et que l'impact est négligeable, mais je m'éloigne du sujet :) Je n'aime pas l'idée de proposer du contenu marketing de grandes pages avec des images, etc. Alors voilà. C'est similaire à ce que d'autres ont suggéré ci-dessus en utilisant un middleware, mais c'est une solution complète qui vous permet de basculer entre HTTP / HTTPS.

Créez d'abord un middleware.

php artisan make:middleware ForceSSL

Voici à quoi devrait ressembler votre middleware.

<?php

namespace App\Http\Middleware;

use Closure;

class ForceSSL
{

    public function handle($request, Closure $next)
    {

        if (!$request->secure()) {
            return redirect()->secure($request->getRequestUri());
        }

        return $next($request);
    }
}

Notez que je ne filtre pas en fonction de l'environnement car j'ai une configuration HTTPS pour le développement local et la production, donc ce n'est pas nécessaire.

Ajoutez ce qui suit à votre routeMiddleware \ App \ Http \ Kernel.php afin de pouvoir choisir le groupe de routage qui doit forcer SSL.

    protected $routeMiddleware = [
    'auth' => \App\Http\Middleware\Authenticate::class,
    'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'can' => \Illuminate\Foundation\Http\Middleware\Authorize::class,
    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
    'forceSSL' => \App\Http\Middleware\ForceSSL::class,
];

Ensuite, je voudrais sécuriser deux groupes de base, connexion / inscription, etc. et tout le reste derrière le middleware Auth.

Route::group(array('middleware' => 'forceSSL'), function() {
/*user auth*/
Route::get('login', 'AuthController@showLogin');
Route::post('login', 'AuthController@doLogin');

// Password reset routes...
Route::get('password/reset/{token}', 'Auth\PasswordController@getReset');
Route::post('password/reset', 'Auth\PasswordController@postReset');

//other routes like signup etc

});


Route::group(['middleware' => ['auth','forceSSL']], function()
 {
Route::get('dashboard', function(){
    return view('app.dashboard');
});
Route::get('logout', 'AuthController@doLogout');

//other routes for your application
});

Confirmez que vos middlewares sont correctement appliqués à vos routes depuis la console.

php artisan route:list

Maintenant que vous avez sécurisé tous les formulaires ou zones sensibles de votre application, la clé est maintenant d'utiliser votre modèle de vue pour définir vos liens sécurisés et publics (non https).

Sur la base de l'exemple ci-dessus, vous rendriez vos liens sécurisés comme suit -

<a href="{{secure_url('/login')}}">Login</a>
<a href="{{secure_url('/signup')}}">SignUp</a>

Les liens non sécurisés peuvent être rendus comme

<a href="{{url('/aboutus',[],false)}}">About US</a></li>
<a href="{{url('/promotion',[],false)}}">Get the deal now!</a></li>

Cela rend une URL complète telle que https: // yourhost / login et http: // yourhost / aboutus

Si vous ne rendiez pas une URL entièrement qualifiée avec http et que vous utilisiez une URL de lien relative ('/ aboutus'), https persisterait après qu'un utilisateur ait visité un site sécurisé.

J'espère que cela t'aides!

na-98
la source
7

Qu'en est-il simplement d'utiliser le fichier .htaccess pour obtenir une redirection https? Cela doit être placé à la racine du projet (pas dans le dossier public). Votre serveur doit être configuré pour pointer vers le répertoire racine du projet.

<IfModule mod_rewrite.c>
   RewriteEngine On
   # Force SSL
   RewriteCond %{HTTPS} !=on
   RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
   # Remove public folder form URL
   RewriteRule ^(.*)$ public/$1 [L]
</IfModule>

J'utilise ceci pour laravel 5.4 (dernière version au moment de la rédaction de cette réponse) mais cela devrait continuer à fonctionner pour les versions de fonctionnalités même si laravel change ou supprime certaines fonctionnalités.

Maulik Gangani
la source
Chrome me donne une erreur: trop de redirections ... On dirait que cela fait une boucle
phoenix
Salut, j'ai mis à jour la réponse. Assurez-vous de mettre ce .htaccess dans le répertoire racine du projet et pointez votre serveur (apache config) vers la racine du projet.
Maulik Gangani
1
@MladenJanjetovic, vous pouvez avoir différents fichiers htaccess pour ces environnements
Burgi
1
@MladenJanjetovic l'avoir dans l'application a certainement ses avantages, mais du point de vue de l'efficacité et de la vitesse, je dirais qu'il est avantageux de l'avoir dans la configuration du serveur afin que vous n'ayez pas à charger Laravel juste pour une redirection. Les configurations spécifiques à l'environnement dans un seul .htaccess versionné peuvent être obtenues en utilisant une condition de réécriture pour vérifier le domaine, quelque chose commeRewriteCond %{HTTP_HOST} productiondomain\.com$ [NC]
Chris
1
Moi aussi, je préfère le placer dans .htaccess dans le répertoire racine, et comme Crhis l'a dit, les paramètres spécifiques à l'environnement peuvent être accomplis ici, quoique un peu moins élégamment que dans la solution de Mladen.
jovan
6

Vous pouvez utiliser RewriteRule pour forcer ssl dans le même dossier .htaccess avec votre index.php
Veuillez ajouter en tant que pièce jointe d'image, l'ajouter avant toutes les règles autres définition de ssl .htaccess

Quy Le
la source
3

dans IndexController.php mettre

public function getIndex(Request $request)
{
    if ($request->server('HTTP_X_FORWARDED_PROTO') == 'http') {

        return redirect('/');
    }

    return view('index');
}

dans AppServiceProvider.php mettre

public function boot()
{
    \URL::forceSchema('https');

}

Dans AppServiceProvider.php, chaque redirection sera dirigée vers l'url https et pour la requête http, nous avons besoin d'une redirection une fois, donc dans IndexController.php Il suffit de faire une redirection

Artur Qaramyan
la source
Pouvez-vous expliquer comment votre réponse résout la question?
sonslikeodd
Veuillez ajouter cette explication à votre réponse.
sonslikeodd
3

Les réponses ci-dessus n'ont pas fonctionné pour moi, mais il semble que Deniz Turan a réécrit le .htaccess d'une manière qui fonctionne avec l'équilibreur de charge de Heroku ici: https://www.jcore.com/2017/01/29/force-https -on-heroku-using-htaccess /

RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Phil
la source
3

J'ajoute cette alternative car j'ai beaucoup souffert de ce problème. J'ai essayé toutes les manières différentes et rien n'a fonctionné. Donc, j'ai trouvé une solution de contournement pour cela. Ce n'est peut-être pas la meilleure solution, mais cela fonctionne -

Pour info, j'utilise Laravel 5.6

if (App::environment('production')) {
    URL::forceScheme('https');
}

production <- Il doit être remplacé par la valeur APP_ENV dans votre fichier .env

thebrownkid
la source
2

Voici comment le faire sur Heroku

Pour forcer SSL sur vos dynos mais pas localement, ajoutez à la fin de votre .htaccess en public /:

# Force https on heroku...
# Important fact: X-forwarded-Proto will exist at your heroku dyno but wont locally.
# Hence we want: "if x-forwarded exists && if its not https, then rewrite it":
RewriteCond %{HTTP:X-Forwarded-Proto} .
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

Vous pouvez tester ceci sur votre machine locale avec:

curl -H"X-Forwarded-Proto: http" http://your-local-sitename-here

Cela définit l'en-tête X-transmis à la forme qu'il prendra sur heroku.

c'est-à-dire qu'il simule la façon dont un dyno heroku verra une requête.

Vous obtiendrez cette réponse sur votre ordinateur local:

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>301 Moved Permanently</title>
</head><body>
<h1>Moved Permanently</h1>
<p>The document has moved <a href="https://tm3.localhost:8080/">here</a>.</p>
</body></html>

C'est une redirection. C'est ce que heroku va rendre à un client si vous définissez le .htaccess comme ci-dessus. Mais cela ne se produit pas sur votre machine locale car X-forwarded ne sera pas défini (nous l'avons simulé avec curl ci-dessus pour voir ce qui se passait).

mwal
la source
2

Si vous utilisez CloudFlare, vous pouvez simplement créer une règle de page pour toujours utiliser HTTPS: Forcer SSL Cloudflare cela redirigera chaque requête http: // vers https: //

En plus de cela, vous devrez également ajouter quelque chose comme ceci à votre fonction boot () \ app \ Providers \ AppServiceProvider.php:

if (env('APP_ENV') === 'production' || env('APP_ENV') === 'dev') {
     \URL::forceScheme('https');
}

Cela garantirait que chaque lien / chemin de votre application utilise https: // au lieu de http: //.

butaminas
la source
2

Une approche un peu différente, testée dans Laravel 5.7

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Str;

class ForceHttps
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {    
        if ( !$request->secure() && Str::startsWith(config('app.url'), 'https://') ) {
            return redirect()->secure($request->getRequestUri());
        }
        return $next($request);
    }
}

PS. Code mis à jour en fonction des commentaires de @ matthias-lill.

Zoli
la source
1
Fonctionne aussi sur Laravel 6.
Rubens
1
l'utilisation des fonctions env () ne fonctionnera pas avec les fichiers de configuration mis en cache. Cela devrait pointer vers la config('app.url')place. En outre, Laravel est livré avec une fonction de chaîne très pratique Str::startsWith(config('app.url'), 'https://').
Matthias Lill
1

Pour Laravel 5.6, j'ai dû changer un peu de condition pour que cela fonctionne.

de:

if (!$request->secure() && env('APP_ENV') === 'prod') {
return redirect()->secure($request->getRequestUri());
}

À:

if (empty($_SERVER['HTTPS']) && env('APP_ENV') === 'prod') {
return redirect()->secure($request->getRequestUri());
}
Priyank
la source
1

Cela a fonctionné pour moi. J'ai créé un code php personnalisé pour forcer le redirection vers https. Incluez simplement ce code dans le header.php

<?php
if (isset($_SERVER['HTTPS']) &&
    ($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] == 1) ||
    isset($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
    $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
  $protocol = 'https://';
}
else {
  $protocol = 'http://';
}
$notssl = 'http://';
if($protocol==$notssl){
    $url = "https://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";?>
    <script> 
    window.location.href ='<?php echo $url?>';
    </script> 
 <?php } ?>
Geek Ashim
la source
1

J'utilise dans Laravel 5.6.28 prochain middleware:

namespace App\Http\Middleware;

use App\Models\Unit;
use Closure;
use Illuminate\Http\Request;

class HttpsProtocol
{
    public function handle($request, Closure $next)
    {
        $request->setTrustedProxies([$request->getClientIp()], Request::HEADER_X_FORWARDED_ALL);

        if (!$request->secure() && env('APP_ENV') === 'prod') {
            return redirect()->secure($request->getRequestUri());
        }

        return $next($request);
    }
}
fomvasss
la source
1

Le moyen le plus simple serait au niveau de l'application. Dans le fichier

app/Providers/AppServiceProvider.php

ajoutez ce qui suit:

use Illuminate\Support\Facades\URL;

et dans la méthode boot (), ajoutez ce qui suit:

$this->app['request']->server->set('HTTPS', true);
URL::forceScheme('https');

Cela devrait rediriger toutes les demandes vers https au niveau de l'application.

(Remarque: ceci a été testé avec laravel 5.5 LTS)

Pinak Saha
la source
1

Vous pouvez simplement accéder à l' application -> Fournisseurs -> AppServiceProvider.php

ajouter deux lignes

utilisez Illuminate \ Support \ Facades \ URL;

URL :: forceScheme ('https');

comme indiqué dans les codes suivants:

use Illuminate\Support\Facades\URL;

class AppServiceProvider extends ServiceProvider
{
   public function boot()
    {
        URL::forceScheme('https');

       // any other codes here, does not matter.
    }
Wria Mohammed
la source
0

Ce travail pour moi dans Laravel 7.x en 3 étapes simples aide d'un middleware:

1) Générez le middleware avec la commande php artisan make:middleware ForceSSL

Intergiciel

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\App;

class ForceSSL
{
    public function handle($request, Closure $next)
    {
        if (!$request->secure() && App::environment() === 'production') {
            return redirect()->secure($request->getRequestUri());
        }

        return $next($request);
    }
}

2) Enregistrez le middleware dans le routeMiddlewarefichier du noyau

Noyau

protected $routeMiddleware = [
    //...
    'ssl' => \App\Http\Middleware\ForceSSL::class,
];

3) Utilisez-le dans vos itinéraires

Itinéraires

Route::middleware('ssl')->group(function() {
    // All your routes here

});

ici la documentation complète sur les middlewares

=========================

.HTACCESS, méthode

Si vous préférez utiliser un .htaccessfichier, vous pouvez utiliser le code suivant:

<IfModule mod_rewrite.c>
    RewriteEngine On 
    RewriteCond %{SERVER_PORT} 80 
    RewriteRule ^(.*)$ https://yourdomain.com/$1 [R,L]
</IfModule>

Cordialement!

Radames E. Hernandez
la source