Я пытаюсь воспользоваться преимуществами нового подписанного промежуточного программного обеспечения в Laravel 5.7, но по какой-то причине сгенерированный подписанный URL-адрес возвращает 403 Invalid Signature.
Я использую последнюю версию Laravel с PHP 7.2
Это мой маршрут 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');
и это в моем контроллере:
$objDemo->tempURL = Url::temporarySignedRoute('report.client', now('America/Panama')->addDays(5), [
'user' => 1,
'client' => 1
]);
URL-адрес создается и отображается примерно так:
Но когда я нажимаю на ссылку, появляется сообщение 403 с сообщением: «Неверная подпись».
Любые идеи? заранее спасибо
-----------ОБНОВИТЬ------------
То, что я уже сделал:
Кажется, ничего не работает, всегда появляется страница с неверной подписью 403
----------- ОБНОВЛЕНИЕ 2 ------------
Хорошо, поэтому после некоторого копания и тестирования я обнаружил, что подписанные маршруты laravel не будут работать, если пользователь вошел в систему, это странно, если я выхожу из системы, тогда маршрут работает отлично, но если я вхожу в систему, он показывает Ошибка 403, может быть, это связано с тем, что Laravel добавляет заголовок cookie сеанса после всего остального? и так подписанный маршрут не работает из-за этого? так оно и должно быть?
Странно, потому что, скажем, я хочу создать временную ссылку для моих пользователей, чтобы что-то загрузить, если они вошли в мое приложение Laravel, они получат это сообщение об ошибке 403 ... :(
------------ ОБНОВЛЕНИЕ 3 ------------------
Я пробовал новую установку laravel и работал отлично, так что это что-то из моего основного приложения Laravel, также попытался установить все зависимости композитора в свежую установку Laravel и по-прежнему отлично работал независимо от статуса входа пользователя, так что это не конфликт с моими зависимостями.






После отладки 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);
}
переменная $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
как вы можете видеть, есть параметры после параметра 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);
}
}
это промежуточное программное обеспечение было внутри групп промежуточного программного обеспечения, так что, надеюсь, это была проблема, если кто-то в будущем экспериментирует с этим, он сможет сначала это проверить.
Я знаю, что это давно опубликовано, но это спасло мне жизнь. Я бы никогда об этом не подумал, так что спасибо!
@Andreas, нет проблем, это цель этого ... я помню, что мне было трудно понять проблему, но я сделал это после долгих поисков.
Если вы используете Heroku, AWS или любой другой сервис, использующий LoadBalancer. Также убедитесь, что прокси-сервер, подключенный к вашему приложению, является доверенным.
Подробнее см. этот ответ.
Попробуйте код ниже:
class TrustProxies extends Middleware
{
protected $proxies = '*';
protected $headers = Request::HEADER_X_FORWARDED_ALL;
}
отредактируйте TrustProxies.php middleware. замените защищенный код $ proxies на защищенный $ proxies = '*'; это поможет решить ошибку 403 на laravel.
@developer_avijit - может быть, попробуйте включить свой комментарий как часть ответа?
По иронии судьбы, я последний раз пробовал этот ответ .. Спасибо, сработало! Было бы полезно, если бы Laravel зарегистрировал ошибку.
По сути, ваши подписи не совпадали, потому что URL-адрес, который вы сгенерировали с помощью \ Illuminate \ Support \ Facades \ URL :: signedRoute, был изменен вашим промежуточным программным обеспечением, что означает, что когда дело дошло до проверки $ request-> hasValidSignature (), это вернуло false.
У меня была аналогичная проблема, когда SendGrid добавлял строки запроса отслеживания UTM к URL-адресу в моем электронном письме (& utm_campaign = website & utm_source = sendgrid.com & utm_medium = email), что изменяло URL-адрес и, в конечном итоге, меняло подпись.
Во время взлома я добавил в свой контроллер следующий код, чтобы убрать дополнительные параметры запроса и повторно использовать подпись:
// Fix issue with sendgrid highjacking 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);
}
у меня была похожая проблема в сумерках, и это был APP_KEY в .env.dusk.testing, который не соответствовал APP_KEY в .env
У меня только что возникла эта проблема, и оказалось, что пустые параметры в URL-адресе никогда не проверяются. Итак, когда вы это сделаете:
URL::temporarySignedRoute('newsletter.verify', now()->addDays(3), ['name' => $name, 'email' => $email])
но имя - это пустая строка (потому что это не обязательно), URL-адрес будет сгенерирован с помощью name= как часть строки запроса, но этот код внутри Laravel
$original = rtrim($url.'?'.Arr::query(Arr::except($request->query(), 'signature')), '?');
не вернет пустой name, поэтому URL-адрес был «изменен» и проверка не прошла. Часто используемое промежуточное ПО ConvertEmptyStringsToNull может иметь какое-то отношение к этому.
У меня была такая же проблема, и я сходил с ума, пока не наткнулся на ответ @LaravDev.
Примечание: я использую Laravel 7, который отличается от страницы web.php.
Мой исходный код выглядел так, который, по сути, просто добавляет переменную к запросу, чтобы мои представления не отображали боковую панель.
Route::middleware(['noSidebar'])->group(function()
{
Auth::routes(['verify' => true]);
});
Мне пришлось удалить шорткод Auth :: routes () и переключить его на полный стек маршрутов Auth. (Обратите внимание, это отличается для каждой версии Laravel)
Route::middleware(['noSidebar'])->group(function()
{
// Authentication Routes...
Route::get('login', 'Auth\LoginController@showLoginForm')->name('login');
Route::post('login', 'Auth\LoginController@login');
Route::post('logout', 'Auth\LoginController@logout')->name('logout');
// Registration Routes...
Route::get('register', 'Auth\RegisterController@showRegistrationForm')->name('register');
Route::post('register', 'Auth\RegisterController@register');
// Password Reset Routes...
Route::get('password/reset', 'Auth\ForgotPasswordController@showLinkRequestForm')->name('password.request');
Route::post('password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail')->name('password.email');
Route::post('password/reset', 'Auth\ResetPasswordController@reset')->name('password.update');
// Confirm Password (added in v6.2)
Route::get('password/confirm', 'Auth\ConfirmPasswordController@showConfirmForm')->name('password.confirm');
Route::post('password/confirm', 'Auth\ConfirmPasswordController@confirm');
// Email Verification Routes...
Route::get('email/verify', 'Auth\VerificationController@show')->name('verification.notice');
Route::post('email/resend', 'Auth\VerificationController@resend')->name('verification.resend');
});
//Moved the routes with tokens in the URL to outside my middleware grouping.
Route::get('email/verify/{id}/{hash}', 'Auth\VerificationController@verify')->name('verification.verify');
Route::get('password/reset/{token}', 'Auth\ResetPasswordController@showResetForm')->name('password.reset');
Тада работает! Спасибо вам всем
Спасибо, я сошел с ума! Я помещал туда свой подписанный URL: Route::localizedGroup(function () {})
У меня был APP_URL=http://localhost в файле .env. Когда я изменил значение на URL-адрес с сервера, проблема была решена.
Я использовал Laravel 8+.
ПОНЯТИЕ СПОСОБА ПРОВЕРКИ ЭЛЕКТРОННОЙ ПОЧТЫ LARAVEL
Понимание способа проверки может помочь вам просто решить эту ошибку.
laravel создает временный подписанный URL-адрес, используя метод URL::temporarySignedRoute(),
этот метод вызывается в verificationUrl(), расположенном по адресу
\vendor\laravel\framework\src\Illuminate\Auth\Notifications\VerifyEmail.php.
/**
* Get the verification URL for the given notifiable.
*
* @param mixed $notifiable
* @return string
*/
protected function verificationUrl($notifiable)
{
return URL::temporarySignedRoute(
'verification.verify',
Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)),
[
'id' => $notifiable->getKey(),
'hash' => sha1($notifiable->getEmailForVerification()),
]
);
}
URL::temporarySignedRoute() создает URL-адреса в соответствии с config('app.url), для которого по умолчанию установлено значение .env('APP_URL').
Итак, если URL-адрес, отправляемый в электронные письма, отличается от URL-адреса, который будет получен laravel во время проверки (время проверки подписи URL-адреса), 403 | возникает недействительная подпись.
Пример:
APP_URL на http://yourdomain.com/, ссылка для подтверждения должна выглядеть как http://yourdomain.com/email/verify/{id}/{hash}. теперь, если вы настроите свои конфигурации сервера для перенаправления на https, возникнет недопустимая подпись, поскольку URL-адрес, который получает laravel, - это https://yourdomain.com/email/verify/{id}/{hash}, а не такой же, как URL-адрес проверки электронной почты.
@LaraDev, ты копаешь абсолютно в правильном направлении.