Laravel 5 - redirecionar para HTTPS

126

Trabalhando no meu primeiro projeto do Laravel 5 e não sei onde ou como colocar a lógica para forçar o HTTPS no meu aplicativo. O argumento decisivo aqui é que existem muitos domínios apontando para o aplicativo e apenas dois em cada três usam SSL (o terceiro é um domínio de fallback, longa história). Então, eu gostaria de lidar com isso na lógica do meu aplicativo, em vez de .htaccess.

No Laravel 4.2, realizei o redirecionamento com este código, localizado em filters.php:

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

Eu estou pensando que o Middleware é onde algo assim deve ser implementado, mas não consigo entender isso usando-o.

Obrigado!

ATUALIZAR

Se você estiver usando o Cloudflare como eu, isso será feito adicionando uma nova regra de página no seu painel de controle.

NightMICU
fonte
Então, o que acontece com o terceiro domínio? Se você forçar https em todas as rotas - o terceiro domínio continuará funcionando?
Laurence
Detectando isso com$_SERVER['HTTP_HOST']
NightMICU
Quanto tempo demorou para regra página cloudflare para entrar em vigor
CodeGuru
Ah, eu tive que ligar o proxy na configuração de DNS haha!
CodeGuru 8/17/17

Respostas:

252

Você pode fazê-lo funcionar com uma classe Middleware. Deixe-me dar uma ideia.

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); 
    }
}

Em seguida, aplique esse middleware a todas as solicitações adicionando a configuração da regra no Kernel.phparquivo, da seguinte maneira:

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'       

];

Na amostra acima, o middleware redirecionará todas as solicitações para https se:

  1. A solicitação atual é fornecida sem protocolo seguro (http)
  2. Se o seu ambiente for igual a production. Portanto, basta ajustar as configurações de acordo com suas preferências.

Cloudflare

Estou usando esse código no ambiente de produção com um SSL WildCard e o código funciona corretamente. Se eu removê && App::environment() === 'production'-lo e testá-lo no localhost, o redirecionamento também funcionará. Portanto, ter ou não um SSL instalado não é o problema. Parece que você precisa prestar muita atenção à sua camada do Cloudflare para ser redirecionado ao protocolo Https.

Editar 23/03/2015

Graças à @Adam Linksugestão de: provavelmente é causado pelos cabeçalhos que o Cloudflare está passando. O CloudFlare provavelmente atinge seu servidor via HTTP e passa um cabeçalho X-Forwarded-Proto que declara que está encaminhando uma solicitação HTTPS. Você precisa adicionar outra linha no seu Middleware que diga ...

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

... confiar nos cabeçalhos que o CloudFlare está enviando. Isso interromperá o loop de redirecionamento

Editar 27/09/2016 - Laravel v5.3

Só precisa adicionar a classe middleware ao webgrupo em 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

    ],
];

Lembre-se de que o webgrupo é aplicado a todas as rotas por padrão, portanto, você não precisa definir webexplicitamente nas rotas nem nos controladores.

Editar 23/08/2018 - Laravel v5.7

  • Para redirecionar uma solicitação, dependendo do ambiente que você pode usar App::environment() === 'production'. Para a versão anterior era env('APP_ENV') === 'production' .
  • Usar \URL::forceScheme('https');realmente não redireciona. Ele apenas cria links https://quando o site é renderizado.
manix
fonte
5
Isso parece estar me dando um loop de redirecionamento ... parece que deve funcionar, no entanto. Não sei se faz alguma diferença, mas estamos usando um SSL Cloudflare. Mas eu não acho que isso mudaria o redirecionamento simples.
NightMICU
3
@ NightMICU Não tenho certeza se você resolveu o problema com o redirecionamento, mas provavelmente é causado pelos cabeçalhos que o Cloudflare está passando. O CloudFlare provavelmente atinge seu servidor via HTTP e passa um cabeçalho X-Forwarded-Proto que declara que está encaminhando uma solicitação HTTPS. Você precisa adicionar outra linha no seu Middleware que diz $request->setTrustedProxies( [ $request->getClientIp() ] );confiar nos cabeçalhos que o CloudFlare está enviando. Isso interromperá o loop de redirecionamento.
Adam Fazer a ligação
2
@manix Awesome. Acabei de passar por esta questão HTTPS neste fim de semana com meu próprio projeto - essas pequenas coisas o frustrarão por horas!
Adam Ligação
8
Excelente resposta! Apenas um detalhe: é melhor usar um redirecionamento 301 para indicar ao Google que é um movimento permanente. Como:return redirect()->secure($request->getRequestUri(), 301);
adriaroca 4/17
4
para aqueles whos sob balanceador de carga ou servidor proxy pode mudar para fixar () para $request->server('HTTP_X_FORWARDED_PROTO') != 'https'isso funciona para mim
Shiro
63

Outra opção que funcionou para mim, no AppServiceProvider, coloque esse código no método de inicialização:

\URL::forceScheme('https');

A função escrita antes de forceSchema ('https') estava errada, seu forceScheme

Constantin Stan
fonte
16
Ei, acabei de descobrir isso pesquisando no Google - observe que na versão 5.4 é\URL::forceScheme('https');
dev
5
No mesmo arquivo, você também pode fazerif($this->app->environment() === 'production'){ $this->app['request']->server->set('HTTPS', true); }
Rory
2
você quis dizer #\URL::forceScheme('https')
Ernest Okot
17
Tenho certeza de que isso é apenas para criar links. Isso não forçará o usuário a https, servirá apenas para links anexados com https: // #
Weston Watson
Sim, aconteceu @WestonWatson. por favor, compartilhe a solução, se encontrado #
Harat
33

Como alternativa, se você estiver usando o Apache, poderá usar o .htaccessarquivo para impor seus URLs ao httpsprefixo. No Laravel 5.4, adicionei as seguintes linhas ao meu .htaccessarquivo e funcionou para mim.

RewriteEngine On

RewriteCond %{HTTPS} !on
RewriteRule ^.*$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Assad Ullah Ch
fonte
2
Isso não é bom se você tiver vários ambientes (desenvolvedor, estágio, produção) do que precisa para definir o SSL em todos eles.
Mladen Janjetovic
@MladenJanjetovic você pode usar RewriteCond %{HTTP_HOST} !=localhostno dev para contornar isso.
Dan
3
@ Dan - Sim, mas você ainda precisará configurá-lo para estágio, local (e isso é mais complicado se os desenvolvedores estiverem usando URLs diferentes no desenvolvimento local, por exemplo, .dev, .local, subdomínios, etc.). Eu preferiria ter esse tipo de lógica no aplicativo.
Mladen Janjetovic
16

para o laravel 5.4, use este formato para obter redirecionamento https em vez 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
fonte
15
Apenas para esclarecer: 1) essas alterações devem ser feitas em app / Providers / AppServiceProvider.php; 2) esta é apenas para definir os links gerados dentro do aplicativo para usar o SSL, não forçá-lo a usar SSL
Phoenix
Oi, Route não está gerando por esse método se eu clicar em um botão que me envie para a próxima rota não está me dando o erro 404
Saket Sinha
Este não é um redirecionamento https. Mas permite a veiculação de https: // site. Se você alterá-lo para http: //, ele também servirá.
franc
12

Semelhante à resposta de manix, mas em um só lugar. Middleware para forçar 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
fonte
Request precisa ser estático?
GFxJamal 4/01
@jRhesk provavelmente não, mas tente e fique à vontade para modificar a resposta
Mladen Janjetovic
8

Isto é para o Larave 5.2.xe superior. Se você deseja ter uma opção para veicular algum conteúdo por HTTPS e outros por HTTP, aqui está uma solução que funcionou para mim. Você pode se perguntar: por que alguém iria querer exibir apenas algum conteúdo por HTTPS? Por que não servir tudo sobre HTTPS?

Embora seja muito bom servir o site inteiro por HTTPS, cortar tudo em HTTPS tem uma sobrecarga adicional no servidor. Lembre-se de que a criptografia não é barata. A pequena sobrecarga também afeta o tempo de resposta do seu aplicativo. Você poderia argumentar que o hardware básico é barato e o impacto é insignificante, mas eu discordo :) Eu não gosto da idéia de veicular páginas de conteúdo de marketing com páginas etc, com imagens etc. em https. Então aqui vai. É semelhante ao que outros sugeriram acima usando middleware, mas é uma solução completa que permite alternar entre HTTP / HTTPS.

Primeiro, crie um middleware.

php artisan make:middleware ForceSSL

É assim que seu middleware deve se parecer.

<?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);
    }
}

Observe que eu não estou filtrando com base no ambiente, porque eu tenho a configuração HTTPS para desenvolvimento e produção local, portanto não há necessidade.

Adicione o seguinte ao seu routeMiddleware \ App \ Http \ Kernel.php para poder escolher qual grupo de rotas deve forçar o 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,
];

Em seguida, eu gostaria de proteger dois grupos básicos de login / inscrição, etc, e tudo mais por trás do 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
});

Confirme se seus middlewares foram aplicados corretamente às suas rotas no console.

php artisan route:list

Agora que você protegeu todos os formulários ou áreas sensíveis do seu aplicativo, a chave agora é usar seu modelo de exibição para definir seus links públicos e seguros (não https).

Com base no exemplo acima, você renderizou seus links seguros da seguinte maneira:

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

Links não seguros podem ser renderizados como

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

O que isso faz é renderizar uma URL totalmente qualificada, como https: // yourhost / login e http: // yourhost / aboutus

Se você não processasse o URL totalmente qualificado com http e usasse um URL de link relativo ('/ aboutus'), o https persistiria depois que um usuário visitar um site seguro.

Espero que isto ajude!

na-98
fonte
7

Que tal usar apenas o arquivo .htaccess para obter o redirecionamento https? Isso deve ser colocado na raiz do projeto (não na pasta pública). Seu servidor precisa ser configurado para apontar para o diretório raiz do projeto.

<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>

Eu uso isso para o laravel 5.4 (versão mais recente até a escrita desta resposta), mas ele deve continuar funcionando para versões de recursos, mesmo que o laravel mude ou remova alguma funcionalidade.

Maulik Gangani
fonte
Chrome dá-me um erro: Demasiados redirecionamentos .. Parece que isso faz com que um loop
Phoenix
Olá, eu atualizei a resposta. Coloque esse arquivo .htaccess no diretório raiz do projeto e aponte seu servidor (apache config) para a raiz do projeto.
Maulik Gangani
1
@MladenJanjetovic você pode ter diferentes htaccess para estes ambientes
Burgi
1
@MladenJanjetovic tê-lo no aplicativo definitivamente tem suas vantagens, mas do ponto de vista de eficiência e velocidade, eu diria que é vantajoso ter isso na configuração do servidor para que você não precise carregar o Laravel apenas para redirecionar. Configurações específicas do ambiente em um único .htaccess de versão pode ser conseguido usando uma condição reescrita para verificar o domínio, algo comoRewriteCond %{HTTP_HOST} productiondomain\.com$ [NC]
Chris
1
Eu também prefiro colocar isso no .htaccess no diretório raiz e, como disse Crhis, as configurações específicas do ambiente podem ser realizadas aqui, embora um pouco menos elegante do que na solução de Mladen.
Jovan
6

Você pode usar RewriteRule para forçar o ssl na mesma pasta .htaccess com o seu index.php
Adicione como anexo de imagem, adicione-o antes de todas as outras regras definindo ssl .htaccess

Quy Le
fonte
3

em IndexController.php colocar

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

        return redirect('/');
    }

    return view('index');
}

em AppServiceProvider.php colocar

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

}

No AppServiceProvider.php, todo redirecionamento será direcionado para o URL https e, para a solicitação http, precisamos redirecionar uma vez, assim, no IndexController.php.

Artur Qaramyan
fonte
Você pode explicar como sua resposta resolve a pergunta?
soundslikeodd
Por favor, adicione esta explicação à sua resposta.
soundslikeodd
3

As respostas acima não funcionaram para mim, mas parece que Deniz Turan reescreveu o .htaccess de uma maneira que funciona com o balanceador de carga do Heroku aqui: 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
fonte
3

Estou adicionando essa alternativa, pois sofri muito com esse problema. Eu tentei de todas as maneiras diferentes e nada funcionou. Então, eu vim com uma solução alternativa para isso. Pode não ser a melhor solução, mas funciona -

Para sua informação, estou usando o Laravel 5.6

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

produção <- deve ser substituído pelo valor APP_ENV no seu arquivo .env

thebrownkid
fonte
2

Veja como fazer isso no Heroku

Para forçar o SSL em seus dynos, mas não localmente, adicione ao final do seu .htaccess em público /:

# 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]

Você pode testar isso em sua máquina local com:

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

Isso define o cabeçalho X encaminhado para o formato que ele assumirá no heroku.

isto simula como um heroku dyno verá uma solicitação.

Você receberá esta resposta em sua máquina 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>

Isso é um redirecionamento. É isso que o heroku vai devolver a um cliente se você definir o .htaccess como acima. Mas isso não acontece na sua máquina local porque o encaminhamento X não será definido (falsificamos com curvatura acima para ver o que estava acontecendo).

mwal
fonte
2

Se você estiver usando o CloudFlare, poderá criar uma regra de página para sempre usar HTTPS: Forçar SSL Cloudflare isso redirecionará toda solicitação http: // para https: //

Além disso, você também teria que adicionar algo assim à sua função boot () \ app \ Providers \ AppServiceProvider.php:

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

Isso garantiria que todos os links / caminhos no seu aplicativo usassem https: // em vez de http: //.

butaminas
fonte
2

Uma abordagem um pouco diferente, testada no 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. Código atualizado com base nos comentários de @ matthias-lill.

Zoli
fonte
1
Também funciona no Laravel 6.
Rubens
1
o uso das funções env () não funcionará com arquivos de configuração em cache. Isso deve apontar para o config('app.url')contrário. Além disso, o Laravel vem com uma função de string muito útil Str::startsWith(config('app.url'), 'https://').
Matthias Lill
1

Para o Laravel 5.6, tive que mudar um pouco a condição para fazê-lo funcionar.

de:

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

Para:

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

Isso funcionou para mim. Eu criei um código php personalizado para forçar o redirecionamento para https. Basta incluir este código no 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 } ?>
Geeky Ashim
fonte
1

Estou usando no Laravel 5.6.28 próximo 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
fonte
1

A maneira mais fácil seria no nível do aplicativo. No arquivo

app/Providers/AppServiceProvider.php

adicione o seguinte:

use Illuminate\Support\Facades\URL;

e no método boot () adicione o seguinte:

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

Isso deve redirecionar todas as solicitações para https no nível do aplicativo.

(Nota: isto foi testado com laravel 5.5 LTS)

Pinak Saha
fonte
1

Você pode simplesmente acessar o aplicativo -> Provedores -> AppServiceProvider.php

adicione duas linhas

use Illuminate \ Support \ Facades \ URL;

URL :: forceScheme ('https');

como mostra os seguintes códigos:

use Illuminate\Support\Facades\URL;

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

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

Este trabalho para mim no Laravel 7.x em 3 etapas simples usando um middleware:

1) Gere o middleware com o comando php artisan make:middleware ForceSSL

Middleware

<?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) Registre o middleware routeMiddlewaredentro do arquivo Kernel

Núcleo

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

3) Use-o em suas rotas

Rotas

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

});

aqui a documentação completa sobre middlewares

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

Método .HTACCESS

Se você preferir usar um .htaccessarquivo, poderá usar o seguinte código:

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

Saudações!

Radames E. Hernandez
fonte