Laravel 5.7 签名路由返回 403 无效签名
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/53892356/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Laravel 5.7 signed route returns 403 invalid signature
提问by LaravDev
I'm trying to take advantage of the new signed middleware in Laravel 5.7, but for some reason the generated signed URL is returning 403 Invalid Signature.
我正在尝试利用 Laravel 5.7 中新的签名中间件,但由于某种原因,生成的签名 URL 返回 403 无效签名。
I'm using the latest Laravel Version, with PHP 7.2
我正在使用最新的 Laravel 版本,带有 PHP 7.2
This is my web.php route:
这是我的 web.php 路由:
Route::get('/report/{user}/{client}', function ($user, $client) {
return ("El usuario es: $user y el cliente es: $client");
})->name('report.client')->middleware('signed');
and this is in my controller:
这是在我的控制器中:
$objDemo->tempURL = Url::temporarySignedRoute('report.client', now('America/Panama')->addDays(5), [
'user' => 1,
'client' => 1
]);
The URL is generated and shows something like this:
生成 URL 并显示如下内容:
But when i click the link the result is a 403 with the message: "Invalid signature"
但是当我单击链接时,结果是 403 消息:“签名无效”
Any ideas? thanks in advance
有任何想法吗?提前致谢
-----------UPDATE------------
- - - - - -更新 - - - - - -
Things i've done already:
我已经做过的事情:
- Try the route without signing, and works perfectly
- Try the route without parameters and only signing
- Try the route without temporary setting and only signing
- Set cloudflare's ip to trusted proxies
- Disable HTTPS, Enable HTTPS
- 无需签名即可尝试路线,并且完美运行
- 试试不带参数只签名的路由
- 尝试没有临时设置和只签名的路线
- 将 cloudflare 的 ip 设置为受信任的代理
- 禁用HTTPS,启用HTTPS
Nothing seems to work, always getting the 403 invalid signature page
似乎没有任何效果,总是得到 403 无效签名页
-----------UPDATE 2------------
-----------更新 2------------
Ok, so after some digging and testing, i found out that laravel signed routes won't work if the user is logged in, this is weird, if i logout then the route works perfectly, but if i log-in then it shows the 403 error, might this be because Laravel adds the session cookie header after everything else? and so the signed route fails because of it? it's this the way it should be?
好的,经过一些挖掘和测试,我发现如果用户登录,laravel 签名的路由将不起作用,这很奇怪,如果我注销,则该路由完美运行,但是如果我登录,则它显示403错误,这可能是因为Laravel在其他一切之后添加了会话cookie标头?所以签名的路由因此而失败?应该是这样吗?
Weird, because let's say i want to create a temporary link for my users to download something, if they are logged into my Laravel app, they will get this 403 error message... :(
奇怪,因为假设我想为我的用户创建一个临时链接来下载某些内容,如果他们登录到我的 Laravel 应用程序,他们将收到此 403 错误消息... :(
------------UPDATE 3------------------
------------更新 3------------
I tried in a fresh installation of laravel and worked perfectly, so it's something from my main Laravel app, also tried to install every composer dependency into the Fresh installation of Laravel, and still worked perfectly no matter the user login status, so it's not a conflict with my dependencies.
我尝试了全新安装的 Laravel 并且运行良好,所以它来自我的主要 Laravel 应用程序,还尝试将每个 composer 依赖项安装到 Laravel 的全新安装中,无论用户登录状态如何,它仍然可以完美运行,所以它不是一个与我的依赖项冲突。
回答by LaravDev
After debugging UrlGenerator::hasValidSignature(), i ended by DD the variables inside UrlGenerator.php
like this:
在调试 UrlGenerator::hasValidSignature() 之后,我以 DD 结束了里面的变量,UrlGenerator.php
如下所示:
public function hasValidSignature(Request $request, $absolute = true)
{
$url = $absolute ? $request->url() : '/'.$request->path();
//dd($url);
$original = rtrim($url.'?'.Arr::query(
Arr::except($request->query(), 'signature')
), '?');
dd($original);
$expires = Arr::get($request->query(), 'expires');
$signature = hash_hmac('sha256', $original, call_user_func($this->keyResolver));
return hash_equals($signature, (string) $request->query('signature', '')) &&
! ($expires && Carbon::now()->getTimestamp() > $expires);
}
the $original
variable showed me what was actually happening with my URL, and showed this:
该$original
变量向我展示了我的 URL 实际发生了什么,并显示了以下内容:
https://example.com/report/1/1?expires=1546586977&settings%5Bincrementing%5D=1&settings%5Bexists%5D=1&settings%5BwasRecentlyCreated%5D=0&settings%5Btimestamps%5D=1&profile%5Bincrementing%5D=1&profile%5Bexists%5D=1&profile%5BwasRecentlyCreated%5D=0&profile%5Btimestamps%5D=1&user%5Bincrementing%5D=1&user%5Bexists%5D=1&user%5BwasRecentlyCreated%5D=0&user%5Btimestamps%5D=1
as you can see there are parameters after the expires parameter, those parameter where aded after the route creation, and that was the problem, this happened because i had a middleware sharing some information to the views like this:
正如您所看到的,expires 参数之后有参数,这些参数是在路由创建之后添加的,这就是问题所在,发生这种情况是因为我有一个中间件向视图共享一些信息,如下所示:
UserDataMiddleware.php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
use App\User;
use App\Setting;
use App\UserProfile;
use Illuminate\Support\Facades\View;
class UserData
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if (Auth::check()) {
$settings = Setting::where('user_id', Auth::user()->id)->first();
$profile = UserProfile::where('user_id', Auth::id())->first();
$user = Auth::user();
View::share('settings', $settings); //Another way to share variables, with the View::share
View::share('profile', $profile);
//Now we need to share owr variables trough the REQUEST to our controllers
$request->merge([
'settings' => $settings,
'profile' => $profile,
'user' => $user
]);
}
return $next($request);
}
}
this middleware was inside the middleware groups, so that was the problem hopefully if someone in the future experiments this, then it could check that first.
这个中间件在中间件组内,所以如果将来有人对此进行实验,那么这就是问题所在,然后它可以先检查一下。
回答by developer avijit
Try below code:
试试下面的代码:
class TrustProxies extends Middleware
{
protected $proxies = '*';
protected $headers = Request::HEADER_X_FORWARDED_ALL;
}
回答by Snaver
Essentially your signatures didn't match because the URL you generated via \Illuminate\Support\Facades\URL::signedRoute was altered by your middleware, meaning when it came to check $request->hasValidSignature() this returned false.
本质上你的签名不匹配,因为你通过 \Illuminate\Support\Facades\URL::signedRoute 生成的 URL 被你的中间件改变了,这意味着在检查 $request->hasValidSignature() 时它返回了 false。
I had a similar issue where SendGrid was adding UTM tracking query strings to the URL's in my email (&utm_campaign=website&utm_source=sendgrid.com&utm_medium=email), which altered the URL and ultimately changes the signature.
我有一个类似的问题,即 SendGrid 将 UTM 跟踪查询字符串添加到我电子邮件中的 URL (&utm_campaign=website&utm_source=sendgrid.com&utm_medium=email),这改变了 URL 并最终更改了签名。
As I hack I added the following code to my controller to strip out the additional query params and re-using the signature:
当我 hack 时,我将以下代码添加到我的控制器中以去除额外的查询参数并重新使用签名:
// Fix issue with sendgrid highHymaning signed URL's with extra query params..
if ($request->query('utm_campaign')) {
$sig = $request->query('signature', '');
$url = route('route-key') . '?signature=' . $sig;
return redirect($url);
}
回答by Lk77
i had similar problem in dusk, and it was the APP_KEY in .env.dusk.testing that was not matching the APP_KEY in .env
我在黄昏时遇到了类似的问题,是 .env.dusk.testing 中的 APP_KEY 与 .env 中的 APP_KEY 不匹配
回答by kbs1
I just had this problem and turns out that empty parameters in the URL will never validate. So when you do this:
我刚刚遇到了这个问题,结果发现 URL 中的空参数永远不会验证。所以当你这样做时:
URL::temporarySignedRoute('newsletter.verify', now()->addDays(3), ['name' => $name, 'email' => $email])
but name is an empty string (because it's not mandatory), URL will get generated with name=
as part of query string, but this code inside Laravel
但是 name 是一个空字符串(因为它不是强制性的),URL 将name=
作为查询字符串的一部分生成,但是 Laravel 中的这段代码
$original = rtrim($url.'?'.Arr::query(Arr::except($request->query(), 'signature')), '?');
will not return the empty name
, hence the URL was 'altered' and validation fails. The commonly used middleware ConvertEmptyStringsToNull
might have something to do with this.
不会返回空的name
,因此 URL 被“改变”并且验证失败。常用的中间件ConvertEmptyStringsToNull
可能与此有关。
回答by David Lartey
If you're using Heroku, AWS or any other service that makes use of a LoadBalancer. Do also ensure that the proxy reaching your application is trusted.
如果您使用 Heroku、AWS 或任何其他使用 LoadBalancer 的服务。还要确保到达您的应用程序的代理是可信的。
See this answerfor more.
有关更多信息,请参阅此答案。