• Почему метод getAttribute не записывает свойства класса?

    @photosho Автор вопроса
    Во всем разобрался. Почему-то думал, что "get*Attribute" вызывается после считывания значения поля из базы данных, но, на самом деле, эта функция вызывается при попытке считать значение поля из объекта ($post->user_id).

    Следовательно, в таком варианте:

    public function getUserIdAttribute($value) {
      $this->author['name'] = User::find($value)->username;
      $this->author['id'] = $value;
      return $value;
    }


    Если просто считать значение свойства $author, оно все еще не будет установлено, оно установится после вызова свойства $user_id ($post->user_id). Следовательно, проблема решается установкой функции преобразования для свойства $author:

    protected $author = [];
    
    public function getAuthorAttribute() {
    	$this->author['id'] = $this->user_id;
    	$this->author['name'] = User::find($this->author['id'], ['username'])->username;
    	return $this->author;
    }
    Ответ написан
    Комментировать
  • Почему для сохранения сессии требуется перезагрузка страницы?

    @photosho Автор вопроса
    При каждом обновлении страницы создается 2 записи Cookie: "XSRF-TOKEN" и "laravel_session". При обычном AJAX-запросе на авторизацию больше Cookie не создается. При AJAX-запросе с последующим перенаправлением PHP-скрипта на любую страницу - в браузере появляется еще одна запись Cookie. Все записи привязаны к корневой директории сайта ("/").

    Притом, после такого запроса страница, с которой была произведена авторизация, получает ответ на свой POST-запрос с кодом "302" + какой-то удачный GET-запрос с того адреса, куда было произведено перенаправление PHP-скрипта.

    Не знаю, насколько это правильно, но из всего перечисленного делаю вывод, что финальное перенаправление PHP-скрипта нужно для обновление записи Cookie в браузере (каким образом - пока не знаю), а значит, и подтверждения авторизации. Без этой записи в Cokie пользователь не мог считаться авторизованным, и простая перезагрузка страницы в браузере, будто бы, "удаляла авторизацию". Почему пользователь при этом считался авторизованным в той же сессии - пока тоже не знаю, возможно, информация о нем как-то кешировалась в переменных на сервере.

    Решил проблему следующим образом. Так как после перенаправления PHP-скрипта на сервере открытой странице с формой авторизации возвращался GET-запрос, сделал вывод, что страница, на которую идет перенаправление, все еще связана с нашей AJAX-функцией. Поэтому перенаправление в PHP-скрипте поставил на страницу "/login/final/", где записал единственную строку:

    echo json_encode(['redirect' => 'update']);

    Как и предвидел: этот массив после выполнения скрипта возвратился браузеру, и по значению "update" параметра "redirect" браузер обновляет текущую страницу. Авторизация работает.

    Всем спасибо за помощь, совет "заглянуть в Cookie" направил меня по нужному пути.
    Ответ написан
  • Почему массив POST пустой?

    @photosho Автор вопроса
    Итак, проблема была в отсутствующем в запросе параметре "X-XSRF-TOKEN" (причем, именно так, а не "X-CSRF-TOKEN", как можно было подумать). Это одна. Вторая - в шифровании этого параметра, но ее до конца понять не удалось.

    С каждым POST-запросом этот параметр должен передаваться на сервер, поэтому, на jQuery будет такой код:

    jQuery.ajaxSetup({
        headers: {'X-XSRF-TOKEN': jQuery('meta[name="csrf-token"]').attr('content')}
    });


    Здесь мы получаем значение параметра "csrf-token" из мета-тегов страницы. А записываем их туда, например, в основном файле представления:

    <meta name="csrf-token" content="{{ csrf_token() }}"/>


    Но даже если все это сделать, сервер все равно будет умирать с сообщением "DecryptException". Информацию об этой проблеме нашел вот здесь. Правда, в итоге сделал вторым способом, так как в первом необходимость добавлять параметр каждому контроллеру показалась страшной.

    То есть, я открыл файл "app/Http/Middleware/VerifyCsrfToken.php" и добавил в него такой код:

    use Symfony\Component\Security\Core\Util\StringUtils;
    ...
    protected function tokensMatch($request) {
    	$token = $request->session()->token();
    	$header = $request->header('X-XSRF-TOKEN');
    	return StringUtils::equals($token, $request->input('_token')) ||
    		($header && StringUtils::equals($token, $header));
    }


    Функцию, конечно же, внутрь класса.

    Хотелось бы в комментариях увидеть ваше мнение. Бабы говорят, что второй вариант может нести какие-то уязвимости, но я пока не очень силен в этих вопросах, поэтому буду рад любому совету по этой теме.
    Ответ написан
    Комментировать