Laravel - сеанс магазину не встановлено на запит


113

Нещодавно я створив новий проект Laravel і дотримувався інструкції щодо аутентифікації. Коли я відвідую або вхід, чи зареєструю маршрут, я отримую таку помилку:

ErrorException in Request.php line 775:
Session store not set on request. (View: C:\Users\Matthew\Documents\test\resources\views\auth\register.blade.php)

Я не редагував жодних основних файлів Laravel, я лише створив представлення даних і додав маршрути до файлу route.php

// Authentication routes
Route::get('auth/login', ['uses' => 'Auth\AuthController@getLogin', 'as' => 'login']);
Route::post('auth/login', ['uses' => 'Auth\AuthController@postLogin', 'as' => 'login']);
Route::get('auth/logout', ['uses' => 'Auth\AuthController@getLogout', 'as' => 'logout']);

// Registration routes
Route::get('auth/register', ['uses' => 'Auth\AuthController@getRegister', 'as' => 'register']);
Route::post('auth/register', ['uses' => 'Auth\AuthController@postRegister', 'as' => 'login']);

Я не маю великого досвіду роботи з Ларавелом, тому, вибачте, будь ласка, моє незнання. Я усвідомлюю, що є ще одне запитання, яке задають те саме, але жодна з відповідей на мене не працює. Дякуємо за прочитане!

Редагувати:

Ось мій register.blade.php за запитом.

@extends('partials.main')

@section('title', 'Test | Register')

@section('content')
    <form method="POST" action="/auth/register">
        {!! csrf_field() !!}
        <div class="ui input">
          <input type="text" name="name" value="{{ old('name') }}" placeholder="Username">
        </div>
        <div class="ui input">
          <input type="email" name="email" value="{{ old('email') }}" placeholder="Email">
        </div>
        <div class="ui input">
          <input type="password" name="password" placeholder="Password">
        </div>
        <div class="ui input">
          <input type="password" name="password_confirmation"placeholder="Confirm Password">
        </div>
        <div>
            <button class="ui primary button" type="submit">Register</button>
        </div>
    </form>
@endsection

пошта register.blade.php код
Chaudhry Waqas

Ви також можете замінити вищенаведені route.php простоRoute::controllers([ 'auth' => 'Auth\AuthController', 'password' => 'Auth\PasswordController', ]);
Chaudhry Waqas

і у вас є маршрути з однаковою назвою, це неправильно, вони повинні мати різні назви
xAoc

@Adamnick Опублікував і спробує замінити його.
mattrick

Як налаштована конфігурація драйвера сеансу?
kipzes

Відповіді:


162

Вам потрібно буде використовувати веб-проміжне програмне забезпечення, якщо вам потрібен стан сеансу, захист CSRF тощо.

Route::group(['middleware' => ['web']], function () {
    // your routes here
});

2
Я насправді маю це, я просто включав відповідні маршрути.
mattrick

Ах, я бачу, що ти маєш на увазі зараз, я перемістив маршрути всередину, і це спрацювало. Дуже дякую!
mattrick

@mattrick: привіт, метрика отримує таку ж помилку .може вам пояснити, куди ви перемістили маршрути всередині проміжного програмного забезпечення, але це відображає помилку "Не знайдено підтримуваного шифрувача. Шифр".
Випін Сінгх

1
@ErVipinSingh вам потрібно буде встановити 32-символьну клавішу в конфігурації програми. Або використовуватиphp artisan key:generate
Cas Bloem

2
Що робити, якщо ваш маршрут входу в API?
Джей

56

При додаванні вашого routesвсередині web middlewareне працює якийсь - небудь причини , то спробуйте додати це $middlewareвKernel.php

protected $middleware = [
        //...
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
];

4
Чорт, це спрацювало для мене, але я не радий, що це "виправлення", а не рішення. Все одно, дякую!
Рав

1
Це зафіксувало це для мене. Дякую @Waiyi
Джош

1
Ваше рішення виправляє мою проблему @Waiyl_Karim
Bipul Roy

Це працювало для мене. Я використовую фронтенд реагування, тому група маршрутів не працює, оскільки я використовую маршрутизатор реакцій для маршрутів.
техцикліст

44

У моєму випадку (використовуючи Laravel 5.3) додавання лише наступних 2 проміжних програм дозволило мені отримати доступ до даних сеансу в моїх маршрутах API:

  • \App\Http\Middleware\EncryptCookies::class
  • \Illuminate\Session\Middleware\StartSession::class

Ціла декларація ( $middlewareGroupsв Kernel.php):

'api' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Session\Middleware\StartSession::class,
            'throttle:60,1',
            'bindings',
        ],

21

Якщо відповідь Cas Bloem не застосовується (тобто ви напевно отримали webпроміжне програмне забезпечення у відповідному маршруті), ви можете перевірити порядок посередництва у вашому ядрі HTTP.

Порядок за замовчуванням у Kernel.phpтакий:

$middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
    ],
];

Зауважте, що VerifyCsrfTokenприходить після StartSession. Якщо ви отримали їх в іншому порядку, залежність між ними також може призвести до Session store not set on request.винятку.


у мене це саме так. я все одно отримаю повідомлення. Я також спробував помістити StartSession та ShareErrorsFromSession у масив $ middleware. Зберігати / кадр також можна записати. (Я використовую Wampserver 3 btw.)
Медді

використовувати 'middleware' => ['web', 'youanother.log'],
Камаро Ламберт

3
Так! Я був німий і думав, що перероблю їх за алфавітом (тому що OCD), і це зламало додаток. На жаль, я не тестував до наступного дня, саме тому я опинився тут. Тільки для запису, за замовчуванням для групи "веб" середнього програмного забезпечення в 5.3 є: EncryptCookies, AddQueuedCookiesToResponse, StartSession, ShareErrorsFromSession, SubstituteBindings, VerifyCsrfToken.
Іксалміда

19

Проблемою може бути те, що ви намагаєтеся отримати доступ до сеансу всередині функції контролера __constructor().

З Laravel 5.3+ це більше неможливо, оскільки він не призначений для роботи в будь-якому випадку, як зазначено в посібнику з оновлення .

У попередніх версіях Laravel ви можете отримати доступ до змінних сеансу або автентифікованого користувача в конструкторі вашого контролера. Це ніколи не передбачалося явною особливістю рамки. У Laravel 5.3 ви не можете отримати доступ до сеансу або автентифікованого користувача в конструкторі контролера, оскільки проміжне програмне забезпечення ще не запущено.

Для отримання додаткової довідкової інформації також прочитати Taylor свою відповідь.

Обхід

Якщо ви все ще хочете використовувати це, ви можете динамічно створити проміжне програмне забезпечення та запустити його в конструкторі, як описано в посібнику з оновлення:

В якості альтернативи ви можете визначити проміжне програмне забезпечення на основі закриття безпосередньо в конструкторі контролера. Перш ніж скористатися цією функцією, переконайтеся, що у вашій програмі працює Laravel 5.3.4 або вище:

<?php

namespace App\Http\Controllers;

use App\User;
use Illuminate\Support\Facades\Auth;
use App\Http\Controllers\Controller;

class ProjectController extends Controller
{
    /**
     * All of the current user's projects.
     */
    protected $projects;

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware(function ($request, $next) {
            $this->projects = Auth::user()->projects;

            return $next($request);
        });
    }
}

1
Дякуємо за пояснення точки __constructor () Очистив мої концепції.
Ashish Choudhary

16

Laravel [5.4]

Моє рішення було використовувати помічник глобальної сесії: session ()

Його функціональність трохи складніше, ніж $ request-> session () .

написання :

session(['key'=>'value']);

штовхає :

session()->push('key', $notification);

отримання :

session('key');

Це не працює, коли ми пишемо змінну сеансу в контролері та використовуємо в іншому контролері :(
Kamlesh

3

У моєму випадку я додав наступні 4 рядки до $ middlewareGroups (у додатку / Http / Kernel.php):

'api' => [
    \App\Http\Middleware\EncryptCookies::class,
    \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
    \Illuminate\Session\Middleware\StartSession::class,
    \App\Http\Middleware\VerifyCsrfToken::class,
    'throttle:60,1',
    'bindings',
],

ВАЖЛИВО: 4 ПРИМІТКИ повинні бути додані перед "дроселем" та "прив'язкою"!

Інакше помилка "CSRF маркер не відповідає" зросте. Я боровся в цьому кілька годин, щоб знайти важливий порядок.

Це дозволило мені отримати доступ до сеансу в моєму API. Я також додав VerifyCsrfToken, коли залучаються файли cookie / сеансів, про це потрібно подбати про CSRF.


Якщо ви пишете apis з laravel, це відповідь, яку ви шукаєте :) або додасте -> stateless () -> redirect ()
Bobby Ax




0

Це не в документації про laravel, я мав годину, щоб досягти цього:

Мій сеанс не зберігався, поки я не застосував метод "збереження" ...

$request->session()->put('lang','en_EN');
$request->session()->save();

0

RouteServiceProvider автоматично до програми маршрутів / web.php автоматично застосовується група веб-програмного забезпечення Laravel 5.3+.

Якщо ви не модифікуєте масив $ middlewareGroups в непідтримуваному порядку, ймовірно, ви намагаєтеся ввести запити як звичайну залежність від конструктора.

Використовувати запит як

public function show(Request $request){

}

замість

public function __construct(Request $request){

}

0

Я отримував цю помилку з Laravel Sanctum. Я виправив це, додавши \Illuminate\Session\Middleware\StartSession::class,до apiгрупи середнього програмного забезпечення в Kernel.php, але пізніше я зрозумів, що це "спрацювало", оскільки api.phpзамість цього були додані мої маршрути аутентифікації web.php, тому Laravel використовував неправильний захист аутентифікації.

Я перемістив ці маршрути сюди, web.phpа потім вони почали правильно працювати з AuthenticatesUsers.phpознакою:

Route::group(['middleware' => ['guest', 'throttle:10,5']], function () {
    Route::post('register', 'Auth\RegisterController@register')->name('register');
    Route::post('login', 'Auth\LoginController@login')->name('login');

    Route::post('password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail');
    Route::post('password/reset', 'Auth\ResetPasswordController@reset');

    Route::post('email/verify/{user}', 'Auth\VerificationController@verify')->name('verification.verify');
    Route::post('email/resend', 'Auth\VerificationController@resend');

    Route::post('oauth/{driver}', 'Auth\OAuthController@redirectToProvider')->name('oauth.redirect');
    Route::get('oauth/{driver}/callback', 'Auth\OAuthController@handleProviderCallback')->name('oauth.callback');
});

Route::post('logout', 'Auth\LoginController@logout')->name('logout');

Я зрозумів, що проблема після отримання ще однієї дивної помилки RequestGuard::logout()не існує.

Це дало мені зрозуміти, що мої власні аут-маршрути викликають методи з ознаки AuthenticationUsers, але я не використовував Auth::routes()для цього. Тоді я зрозумів, що Laravel використовує веб-охорону за замовчуванням, і це означає, що маршрути повинні бути в routes/web.php.

Ось як виглядають мої налаштування зараз із Sanctum та зв'язаним додатком Vue SPA:

Kernel.php

protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        // \Illuminate\Session\Middleware\AuthenticateSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],

    'api' => [
        EnsureFrontendRequestsAreStateful::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
        'throttle:60,1',
    ],
];

Примітка. З Laravel Sanctum та з однодоменним Vue SPA ви використовуєте файли cookie httpOnly для сеансового файлу cookie та запам’ятайте мені cookie та незахищені файли cookie для CSRF, тому ви використовуєте webохорону для auth та будь-який інший захищений маршрут, що повертається JSON, повинен використовувати auth:sanctumпроміжне програмне забезпечення.

config / auth.php

'defaults' => [
    'guard' => 'web',
    'passwords' => 'users',
],

...

'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],

    'api' => [
        'driver' => 'token',
        'provider' => 'users',
        'hash' => false,
    ],
],

Тоді ви можете мати юнят тести , такі як це, де критично Auth::check(), Auth::user()і Auth::logout()робота , як очікується , з мінімальною конфігурацією і максимальним використанням AuthenticatesUsersі RegistersUsersрисами.

Ось кілька моїх тестових одиниць реєстрації:

TestCase.php

/**
 * Creates and/or returns the designated regular user for unit testing
 *
 * @return \App\User
 */
public function user() : User
{
    $user = User::query()->firstWhere('email', 'test-user@example.com');

    if ($user) {
        return $user;
    }

    // User::generate() is just a wrapper around User::create()
    $user = User::generate('Test User', 'test-user@example.com', self::AUTH_PASSWORD);

    return $user;
}

/**
 * Resets AuthManager state by logging out the user from all auth guards.
 * This is used between unit tests to wipe cached auth state.
 *
 * @param array $guards
 * @return void
 */
protected function resetAuth(array $guards = null) : void
{
    $guards = $guards ?: array_keys(config('auth.guards'));

    foreach ($guards as $guard) {
        $guard = $this->app['auth']->guard($guard);

        if ($guard instanceof SessionGuard) {
            $guard->logout();
        }
    }

    $protectedProperty = new \ReflectionProperty($this->app['auth'], 'guards');
    $protectedProperty->setAccessible(true);
    $protectedProperty->setValue($this->app['auth'], []);
}

LoginTest.php

protected $auth_guard = 'web';

/** @test */
public function it_can_login()
{
    $user = $this->user();

    $this->postJson(route('login'), ['email' => $user->email, 'password' => TestCase::AUTH_PASSWORD])
        ->assertStatus(200)
        ->assertJsonStructure([
            'user' => [
                ...expectedUserFields,
            ],
        ]);

    $this->assertEquals(Auth::check(), true);
    $this->assertEquals(Auth::user()->email, $user->email);
    $this->assertAuthenticated($this->auth_guard);
    $this->assertAuthenticatedAs($user, $this->auth_guard);

    $this->resetAuth();
}

/** @test */
public function it_can_logout()
{
    $this->actingAs($this->user())
        ->postJson(route('logout'))
        ->assertStatus(204);

    $this->assertGuest($this->auth_guard);

    $this->resetAuth();
}

Я переосмислив registeredі authenticatedметоди в ауто рисах Laravel, щоб вони повернули об'єкт користувача замість лише 204 ВАРІАНТІВ:

public function authenticated(Request $request, User $user)
{
    return response()->json([
        'user' => $user,
    ]);
}

protected function registered(Request $request, User $user)
{
    return response()->json([
        'user' => $user,
    ]);
}

Подивіться на код постачальника щодо авторських рис. Ви можете використовувати їх недоторканими, а також ці два вищевказані методи.

  • vendor / laravel / ui / auth-backend / RegistersUsers.php
  • vendor / laravel / ui / auth-backend / AuthenticationUsers.php

Ось мої дії Vue SPA для входу в систему:

async login({ commit }, credentials) {
    try {
        const { data } = await axios.post(route('login'), {
            ...credentials,
            remember: credentials.remember || undefined,
        });

        commit(FETCH_USER_SUCCESS, { user: data.user });
        commit(LOGIN);

        return commit(CLEAR_INTENDED_URL);
    } catch (err) {
        commit(LOGOUT);
        throw new Error(`auth/login# Problem logging user in: ${err}.`);
    }
},

async logout({ commit }) {
    try {
        await axios.post(route('logout'));

        return commit(LOGOUT);
    } catch (err) {
        commit(LOGOUT);

        throw new Error(`auth/logout# Problem logging user out: ${err}.`);
    }
},

Мені знадобилося більше тижня, щоб отримати Laravel Sanctum + однодоменний Vue SPA + авторизований тест, який працює на моєму рівні, тому, сподіваюся, моя відповідь тут може допомогти заощадити інший час у майбутньому.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.