web-dev-qa-db-fra.com

Laravel 5 - redirection vers HTTPS

Je travaille sur mon premier projet Laravel 5 sans savoir où et comment placer la logique pour forcer HTTPS sur mon application. L’essentiel ici est qu’il existe de nombreux domaines pointant vers l’application et que seulement deux sur trois utilisent le protocole SSL (le troisième est un domaine de repli, histoire longue). Je voudrais donc gérer cela dans la logique de mon application plutôt que .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 Middleware est l'endroit où quelque chose comme ceci devrait être implémenté mais je ne peux pas comprendre cela en l'utilisant.

Merci!

UPDATE

Si vous utilisez Cloudflare comme je le suis, pour cela, ajoutez une nouvelle règle de page dans votre panneau de configuration.

96
NightMICU

Vous pouvez le faire fonctionner avec une classe Middleware. Laisse-moi te 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 demande ajoutant la définition de la règle dans le fichier Kernel.php, comme suit:

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 en cours n’a pas de 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 une WildCard SSL 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. On dirait que vous devez garder une très grande attention sur votre couche Cloudflare afin d'être redirigé vers le protocole Https.

Modifier le 23/03/2015

Grâce à la suggestion de @Adam Link: elle est probablement causée par les en-têtes que Cloudflare passe. CloudFlare frappe probablement votre serveur via HTTP et passe un en-tête X-Forwarded-Proto qui déclare qu'il transfère une demande HTTPS. Vous devez ajouter une autre ligne dans votre middleware qui dit ...

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

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

Édition du 27/09/2016 - Laravel v5.3

Il suffit d’ajouter la classe de middleware au groupe web de 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 groupe web est appliqué à chaque route par défaut. Vous n'avez donc pas besoin de définir explicitement web dans les routes ni dans les contrôleurs.

Édité le 23/08/2018 - Laravel v5.7

  • Pour rediriger une demande en fonction de l'environnement, vous pouvez utiliser App::environment() === 'production'. Pour la version précédente était env('APP_ENV') === 'production'.
  • Utiliser \URL::forceScheme('https'); ne redirige pas réellement. Il ne fait que créer des liens avec https:// une fois que le site Web est rendu.
211
manix

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 forceScheme ('https') était fausse, forceScheme

49
Constantin Stan

Si vous utilisez Apache, vous pouvez également utiliser le fichier .htaccess pour que vos URL utilisent le préfixe https. Sur Laravel 5.4, j'ai ajouté les lignes suivantes à mon fichier .htaccess et cela a fonctionné pour moi.

RewriteEngine On

RewriteCond %{HTTPS} !on
RewriteRule ^.*$ https://%{HTTP_Host}%{REQUEST_URI} [L,R=301]
26
Assad Ullah Ch

for 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');
    }
}
15
Arun Yokesh

Semblable à la réponse de manix mais à un 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);
    }
}
10
Mladen Janjetovic

C'est pour Larave 5.2.x et supérieur. Si vous souhaitez avoir la possibilité de servir 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 ne servir que du contenu via HTTPS? Pourquoi ne pas tout servir via HTTPS?

Bien que ce soit tout à fait correct de servir le site entier via HTTPS, tout couper sur HTTPS entraîne une surcharge supplémentaire sur votre serveur. Rappelez-vous 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 dire 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 servir du contenu marketing sur de grandes pages avec des images, etc. au-dessus de https. Alors voilà. C'est semblable à ce que d'autres suggèrent d'utiliser un middleware, mais c'est une solution complète qui vous permet de basculer entre HTTP et HTTPS.

Commencez par créer 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 la configuration HTTPS pour le développement local et la production, il n'y en a donc pas besoin.

Ajoutez les éléments suivants à votre fichier routeMiddleware\App\Http\Kernel.php afin que vous puissiez choisir quel groupe de routes doit forcer le protocole 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, j'aimerais sécuriser deux groupes de base de 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 itinéraires depuis la console.

php artisan route:list

Maintenant que vous avez sécurisé tous les formulaires ou les zones sensibles de votre application, vous devez maintenant 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 rendrez 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 pleinement qualifiée telle que https: // votrehôte/login et http: // votrehôte/aboutus

Si vous ne présentiez pas d'URL qualifiée complète avec http et n'utilisiez pas d'URL de lien relatif ("/ aboutus"), https persisterait alors lorsqu'un utilisateur visitait un site sécurisé.

J'espère que cela t'aides!

6
na-98

Qu'en est-il de simplement utiliser . Htaccess fichier pour obtenir la redirection https? Cela devrait être placé dans la racine du projet (pas dans un 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 l'écriture de cette réponse), mais cela devrait continuer à fonctionner pour les versions de fonctions, même si laravel change ou supprime certaines fonctionnalités.

5
Maulik Gangani

Vous pouvez utiliser RewriteRule pour forcer SSL dans le même dossier .htaccess avec votre index.php
S'il vous plaît ajouter en tant que pièce jointe, ajoutez-le avant toutes les autres règles setting ssl .htaccess

5
Quy Le

dans IndexController.php put

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

        return redirect('/');
    }

    return view('index');
}

dans AppServiceProvider.php put

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 unique. Dans IndexController.php, nous avons simplement besoin de redirection unique.

3
Artur Qaramyan

Les réponses ci-dessus n'ont pas fonctionné pour moi, mais il apparaît que Deniz Turan a récrit le fichier .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]
3
Phil

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());
}
1
Priyank

Cela a fonctionné pour moi. J'ai créé un code php personnalisé pour le forcer à le rediriger vers https. Il suffit d'inclure ce code sur 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 } ?>
1
Geeky Ashim

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

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

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

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

1
butaminas

Voici comment faire sur Herok

Pour forcer SSL sur votre dynos mais pas localement, ajoutez à la fin de votre .htaccess in 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 cela 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 comment un dyno de 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 redonner à un client si vous définissez le .htaccess comme ci-dessus. Mais cela ne se produit pas sur votre ordinateur local car X-forwarded ne sera pas défini (nous le simulons avec curl ci-dessus pour voir ce qui se passait).

1
mwal

Une approche légèrement différente, testée dans Laravel 5.7

<?php

namespace App\Http\Middleware;

use Closure;

class ForceHttps
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        $app_url = env('APP_URL');

        if ( !$request->secure() && substr($app_url, 0, 8) === 'https://' ) {
            return redirect()->secure($request->getRequestUri());
        }
        return $next($request);
    }
}
1
Zoli

J'utilise dans Laravel 5.6.28 le 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);
    }
}
1
fomvasss

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)

1
Pinak Saha

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

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

1
thebrownkid