Php Laravel 403仅在Nginx Web服务器上的签名无效 问题

Php Laravel 403仅在Nginx Web服务器上的签名无效 问题,php,laravel,nginx,https,Php,Laravel,Nginx,Https,我正在通过从laravels文档复制和粘贴的laravels“temporarySignedRoute”函数创建签名URL,在我的web服务器上,URL显示为403无效签名。签名的URL在我的本地机器上工作,但在将其上载到我的测试服务器时,会出现如下所示的错误 我试过的 我一直在寻找一个解决方案有一段时间了,现在已经尝试了许多已经发布在堆栈溢出上的解决方案,但似乎没有什么能解决我的问题 我尝试了以下所有方法: 通过AppServiceProvider强制所有路由到https,这强制所有url

我正在通过从laravels文档复制和粘贴的laravels“temporarySignedRoute”函数创建签名URL,在我的web服务器上,URL显示为403无效签名。签名的URL在我的本地机器上工作,但在将其上载到我的测试服务器时,会出现如下所示的错误

我试过的 我一直在寻找一个解决方案有一段时间了,现在已经尝试了许多已经发布在堆栈溢出上的解决方案,但似乎没有什么能解决我的问题

我尝试了以下所有方法:

  • 通过AppServiceProvider强制所有路由到https,这强制所有url都是https,但给出了相同的结果
  • 我试着改变Nginx的配置

  • 我还尝试添加TrustProxies中间件,并将代理配置为“*”或全部,如laravel的文档中所述,结果相同

  • 停止web服务器强制域使用https测试是否是https导致的,结果相同

--更新-- 我进入了
vendor/laravel/framework/src/illumb/Routing/UrlGenerator.php
,试图在项目中寻找任何线索。我决定数据转储(dd)出它在本地和托管项目上比较的标记,这就是结果。代码也显示在下面

public function hasValidSignature(Request $request, $absolute = true)
{
    $url = $absolute ? $request->url() : '/'.$request->path();

    $original = rtrim($url.'?'.Arr::query(
        Arr::except($request->query(), 'signature')
    ), '?');

    $expires = $request->query('expires');

    $signature = hash_hmac('sha256', $original, call_user_func($this->keyResolver));
    dd($signature . " :: " . $request->query('signature', ''));
    return  hash_equals($signature, (string) $request->query('signature', '')) &&
           ! ($expires && Carbon::now()->getTimestamp() > $expires);
}
本地项目

托管项目

因此,令牌没有在我的web服务器上传递,而是在我的本地服务器上传递。我注意到的另一件事是,web服务器令牌始终是相同的,无论发生什么情况都不会更改

可以查看我当前的Nginx配置


我当前的虚拟主机配置是。

我认为这可能是问题所在。
尝试将配置文件中的位置块更改为

try_文件$uri$uri//index.php?$query_字符串

我想您错过了
,它位于索引和查询字符串之间

更新此文件并确保重新加载您的Nginx服务器。
sudo服务nginx重新加载


让我知道这是否有效

这不是Nginx错误。如果您检查
illumb\Routing\Middleware\ValidateSignature
它抛出一个
illumb\Routing\Exceptions\InvalidSignatureException
以403状态中止请求,这就是laravel处理无效签名URL的方式。我所做的, 创建了一个自定义签名中间件,该中间件扩展了实际的ValidateSignature

<?php

namespace App\Http\Middleware;

use App\Exceptions\InvalidEmailVerificationException;
use Closure;
use Illuminate\Routing\Middleware\ValidateSignature as MiddleWare;

class ValidateSignature extends Middleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if ($request->hasValidSignature()) {
            return $next($request);
        }

        throw new InvalidEmailVerificationException;
    }
}
然后将
App\Http\Kernel.php$routeMiddleware
中的签名中间件更改为
'signed'=>\App\Http\middleware\ValidateSignature::class,

在403.blade.php视图中,可以将消息显示为

@if ($exception instanceof \App\Exceptions\InvalidEmailVerificationException)
                            <h1 class="text-ginormous">Snap!</h1>
                            <h4 class="quick-error-description">Verification token expired.</h4>
                            @if (session('resent'))
                                <div class="alert alert-success" role="alert">
                                    {{ __('A fresh verification link has been sent to your email address.') }}
                                </div>
                            @endif
                            <p class="error-description">{{ $exception->getMessage() }}</p>

                            <a href="{{ route('verification.resend') }}" class="button-solid button-error mb-3" data-no-pjax>Email me a new link</a>
@endif
@if($exception instanceof\App\Exceptions\InvalidEmailVerificationException)
断裂
验证令牌已过期。
@if(会话(“重新发送”))
{{{{{('新的验证链接已发送到您的电子邮件地址。')}
@恩迪夫

{{{$exception->getMessage()}

@恩迪夫
库马尔·巴恩瓦尔亲王的帖子修复了我当时的问题,我最近重新发现了这个问题的另一个版本,同时尝试在相同的设置中使用docker,我想我会在这里发布,以防有人有同样的问题

我们正在使用代理服务器并验证docker laravel项目,所有项目都有TrustProxies设置,然后我们在
AppServiceProvider.php
中强制HTTPS,这使得AJAX调用能够工作。这会导致问题,因为项目本身没有加密,但它生成的所有URL都认为是加密的,因为我们正在强制它。当代理在请求中传递URL时,它是http,而项目需要HTTPS

我找到了一个解决方案,它不是最干净的,而且可能是更好的解决方案,但我制作了一个中间件,用于所有项目的签名路由,基本上它只是更改请求中的url,以确保项目在生产中的安全。这不是不安全的,因为代理处理安全性,并且这仅在签名路由上

<?php

namespace App\Http\Middleware;

use Closure;

class SecureSignedURL
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if(config('app.env') === 'production' || config('app.env') === 'staging') {
            $request->server->set('HTTPS', 'ON');
        }
        return $next($request);
    }
}
下面是仅在已签名路由上运行的中间件

<?php

namespace App\Http\Middleware;

use Closure;

class SecureSignedURL
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if(config('app.env') === 'production' || config('app.env') === 'staging') {
            $request->server->set('HTTPS', 'ON');
        }
        return $next($request);
    }
}
我也不知道这是否是最好的修复方法,这是Laravel中一个非常模糊的bug。如果你有任何更好的解决方法的建议,我愿意接受建议


我以前的Github问题可能会有所帮助:

您可以发布您的Nginx配置吗?我不确定,但它看起来像是Nginx配置中的一个问题。可以在这里查看当前的Nginx配置。您正在使用虚拟主机吗?因为上面提到的配置有根或服务器名或代理请求(如果您正在使用的话)?介意显示虚拟主机的配置吗?还有一件事,本地和服务器的.env有什么区别。我的意思是,会话驱动程序或缓存驱动程序引擎在这两个方面是不同的?数据库还是文件?服务器和本地中的.env几乎相同,减去指向不同MySQL服务器的SQL服务器的主机名。我使用的是数据库而不是文件。你可以在这里查看虚拟主机。尝试更改位置块以尝试\u文件$uri$uri//index.php?$query\u字符串;我认为您错过了索引和查询字符串之间的“?”。更新此文件并确保重新加载nginx服务器sudo service nginx reload`让我知道这是否有效。使用上述方法解决此问题后,我遇到了另一个问题,“UrlGenerator.php”中的签名在https上不同。我找到了这里详细介绍的解决方案。
Route::group(['middleware' => ['secure_signed_Url', 'signed']], function () {
        route::get('/exampleurl1', 'TestController@route_exampleurl1_signed')->name('exampleurl1.signed');
        route::get('/exampleurl2', 'Template\TemplateController@route_exampleurl2_signed')->name('exampleurl2.signed');
});