Я недавно обновил свой проект с Laravel 5.6 до 5.7 и добавил шаги проверки электронной почты, описанные в документах Laravel, в мой проект.
Все отлично работает на моей машине разработки (это http), но когда я обновляю свой рабочий сервер (который https) со всеми изменениями, то когда отправляет 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);
}
Когда я нажимаю кнопку или вставляю ссылку в браузере и нажимаю ввод, я получаю следующие сообщения журнала:
(Я сменил реальный домен по понятным причинам …. не пытайтесь продать свой сайт или что-то в этом роде)
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');
}
Задача ещё не решена.
Других решений пока нет …