Недавно я обновил свой проект с Laravel 5.6 до 5.7 и добавил в свой проект шаги проверки электронной почты, описанные в документации Laravel. Все отлично работает на моей машине разработки (это http), но когда я обновляю свой производственный сервер (это https) со всеми изменениями, тогда, когда laravel отправляет мне электронное письмо со ссылкой (подписанный маршрут), он сгенерировал для меня, чтобы я нажал кнопку или вставил в мой браузер laravel, похоже, не может проверить созданную подпись. Побочный эффект заключается в том, что каждый раз, когда я нажимаю кнопку или вставляю ссылку в браузер, я получаю сообщение об ошибке:
403 Извините, у вас нет прав доступа к этой странице.
Что я проследил до сих пор, так это то, что я нашел код в классе ValidateSignature.php laravel и добавил несколько сообщений журнала.
public function handle($request, Closure $next)
{
Log::info('checking signature');
if ($request->hasValidSignature()) {
Log::info('signature is valid');
return $next($request);
}
Log::info('throwing InvalidSignatureException');
throw new InvalidSignatureException;
}
И, более конкретно, я проследил точную проблему внутри модуля laravel UrlGenerator.php. Я добавил журналы следующим способом:
public function hasValidSignature(Request $request)
{
$original = rtrim($request->url().'?'.Arr::query(
Arr::except($request->query(), 'signature')
), '?');
$expires = Arr::get($request->query(), 'expires');
$signature = hash_hmac('sha256', $original, call_user_func($this->keyResolver));
Log::info('url: '.$original);
Log::info('expire: '.$expires);
Log::info(' new signature: '.$signature);
Log::info('link signature: '.$request->query('signature', ''));
Log::info('hash equals: '.hash_equals($signature, $request->query('signature', '')));
Log::info('expired: '.!($expires && Carbon::now()->getTimestamp() > $expires));
return hash_equals($signature, $request->query('signature', '')) &&
! ($expires && Carbon::now()->getTimestamp() > $expires);
}
Когда я нажимаю кнопку или вставляю ссылку в браузере и нажимаю Enter, я получаю следующие сообщения журнала: (Я изменил свой реальный домен по очевидным причинам .... не пытайтесь продавать мой сайт или что-то в этом роде)
checking signature
url: http://www.example.com/email/verify/2?expires=1538012234
expire: 1538012234
new signature: 1326b9e7402a51e0f05ddf1cb14f1e14852b4c5f0d1d6e726554806e7d85b4b1
link signature: e1d3ad5dc88faa8d8b0e6890ef60e216b75d26ef7ed5c6ab1cc661548e0ad8df
hash equals:
expired: 1
throwing InvalidSignatureException
Поэтому я не знаю, заключается ли ошибка в логике, в которой laravel создает начальную подпись, или когда он пытается ее проверить. Однако, как я уже сказал, все это отлично работает на моей машине разработки. Я очистил кеш, очистил маршруты, обновил код до последней версии, перезагрузил сервер - все, что я мог придумать. Любая помощь будет принята с благодарностью.
**** ОБНОВИТЬ *****
Я копнул немного глубже и сузил проблему. Не могу поверить, что не видел этого прошлой ночью. Если мы внимательно посмотрим на журналы вывода, перечисленные выше, одно сообщение журнала
url: http://www.example.com/email/verify/2?expires=1538012234
показывает нам проблему. Итак, как я уже сказал, моя машина разработки - это http, но мой живой сервер - https. Сегодня утром (после хорошего 4-часового сна) я вижу, что журнал показывает нам, что каким-то образом логика в методе hasValidSignature () получает маршрут с http вместо https. Поэтому, когда я возвращаюсь к своему электронному письму, ссылка в электронном письме - https, если я вставляю URL-адрес в свой браузер, он имеет https, и в моем браузере после того, как эта логика возвращает ошибку 403, браузер все еще показывает https. Итак, теперь мы можем сосредоточиться на том, как мой маршрут / URL-адрес преобразуется в http? Я действительно борюсь здесь, потому что я понятия не имею, как обрабатывается этот URL-адрес, поскольку / email / verify даже не указан ни в одном из моих файлов маршрутов (о которых я знаю), и я не могу сказать, что понимаю, что искать в капюшон для этого тоже, так что я действительно надеюсь на некоторую помощь здесь.
Также вот настройки в моем файле .env:
APP_USE_HTTPS=true
APP_URL=https://www.example.com
APP_ENV=production
И в методе загрузки AppServiceProvider у меня есть
public function boot()
{
Schema::defaultStringLength(191);
if (env('APP_USE_HTTPS'))
{
Log::info('forcing URLs to use https');
\URL::forceScheme('https');
}
I am not sure where that route goes
- не бойтесь читать исходный код. Это один из лучших способов учиться. Погрузитесь в кодовую базу Laravel и проследите по этому маршруту на протяжении всего жизненного цикла запроса / ответа. Лучший способ понять эти вещи - следовать им, шаг за шагом. - person fubar   schedule 27.09.2018