Laravel - Penyimpanan sesi tidak diatur berdasarkan permintaan

113

Saya baru-baru ini membuat proyek Laravel baru dan mengikuti panduan tentang Otentikasi. Saat saya mengunjungi rute login atau register, saya mendapatkan error berikut:

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

Saya belum mengedit file inti Laravel, saya hanya membuat tampilan dan menambahkan rute ke file routes.php saya

// 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']);

Saya tidak memiliki banyak pengalaman dengan Laravel, jadi mohon maaf atas ketidaktahuan saya. Saya sadar bahwa ada pertanyaan lain yang menanyakan hal yang sama, tetapi tidak satu pun dari jawaban tersebut yang tampaknya berhasil untuk saya. Terima kasih sudah membaca!

Edit:

Ini register.blade.php saya seperti yang diminta.

@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
mattrick
sumber
post register.blade.php code
Chaudhry Waqas
Anda juga dapat mengganti routes.php di atas dengan hanyaRoute::controllers([ 'auth' => 'Auth\AuthController', 'password' => 'Auth\PasswordController', ]);
Chaudhry Waqas
dan Anda memiliki rute dengan nama yang sama, itu salah, mereka harus memiliki nama yang berbeda
xAoc
@Adamnick Diposting dan akan mencoba menggantinya.
mattrick
Bagaimana konfigurasi driver sesi Anda disetel?
kipzes

Jawaban:

163

Anda harus menggunakan middleware web jika Anda memerlukan status sesi, perlindungan CSRF, dan banyak lagi.

Route::group(['middleware' => ['web']], function () {
    // your routes here
});
Cas Bloem
sumber
2
Sebenarnya saya punya itu, saya hanya memasukkan rute yang relevan.
mattrick
Ah, saya mengerti apa yang Anda maksud sekarang, saya memindahkan rute ke dalam dan itu berhasil. Terima kasih banyak!
mattrick
@mattrick: hai metrix mendapatkan kesalahan yang sama. dapatkah Anda menjelaskan ke mana Anda memindahkan rute di dalam middleware tetapi itu menunjukkan kesalahan "Tidak ditemukan pengenkripsi yang didukung. Sandi".
Vipin Singh
1
@ErVipinSingh Anda harus menyetel kunci 32 karakter di konfigurasi aplikasi Anda. Atau gunakanphp artisan key:generate
Cas Bloem
2
Bagaimana jika rute login Anda ada di API?
Jay Bienvenu
56

Jika menambahkan routesbagian dalam web middlewareAnda tidak berfungsi karena alasan apa pun, coba tambahkan ini ke $middlewaredalamKernel.php

protected $middleware = [
        //...
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
];
Waiyl Karim
sumber
4
Sial, ini berhasil untuk saya, tetapi saya tidak senang ini adalah "perbaikan", bukan solusi. Terima kasih!
Rav
1
Ini memperbaikinya untuk saya. Terima kasih @Waiyi
Josh
1
Solusi Anda memperbaiki masalah saya @WaiylKarim
Bipul Roy
Ini berhasil untuk saya. Saya menggunakan react frontend sehingga grup rute tidak berfungsi karena saya menggunakan react router untuk rute.
Techcyclist
44

Dalam kasus saya (menggunakan Laravel 5.3) menambahkan hanya 2 middleware berikut memungkinkan saya mengakses data sesi di rute API saya:

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

Deklarasi keseluruhan ( $middlewareGroupsdi Kernel.php):

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

Jika jawaban Cas Bloem tidak berlaku (yaitu, Anda pasti mendapatkan webmiddleware pada rute yang berlaku), Anda mungkin ingin memeriksa urutan middlewares di Kernel HTTP Anda.

Urutan defaultnya Kernel.phpadalah ini:

$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,
    ],
];

Perhatikan yang VerifyCsrfTokenmuncul setelahnya StartSession. Jika Anda mendapatkan ini dalam urutan yang berbeda, ketergantungan di antara keduanya juga dapat mengarah pada Session store not set on request.pengecualian.

Hugh Grigg 葛 修 远
sumber
saya memilikinya persis seperti itu. í masih menerima pesannya. Saya juga mencoba meletakkan StartSession dan ShareErrorsFromSession di array $ middleware. Storate / frameword juga dapat ditulisi. (Saya menggunakan Wampserver 3 btw.)
Meddie
gunakan 'middleware' => ['web', 'youanother.log'],
Kamaro Lambert
3
Ya! Saya bodoh dan berpikir saya akan menyusun ulang sesuai abjad (karena OCD) dan itu merusak aplikasi. Sayangnya, saya tidak menguji sampai keesokan harinya, itulah sebabnya saya berakhir di sini. Sekadar catatan, urutan default untuk grup middleware "web" di 5.3 adalah: EncryptCookies, AddQueuedCookiesToResponse, StartSession, ShareErrorsFromSession, SubstituteBindings, VerifyCsrfToken.
Ixalmida
19

Masalahnya bisa jadi Anda mencoba mengakses sesi Anda di dalam __constructor()fungsi pengontrol Anda .

Dari Laravel 5.3+ ini tidak mungkin lagi karena itu tidak dimaksudkan untuk berfungsi, seperti yang dinyatakan dalam panduan peningkatan .

Di versi Laravel sebelumnya, Anda dapat mengakses variabel sesi atau pengguna yang diautentikasi di konstruktor pengontrol Anda. Ini tidak pernah dimaksudkan sebagai fitur eksplisit dari framework. Di Laravel 5.3, Anda tidak dapat mengakses sesi atau pengguna terotentikasi di konstruktor pengontrol Anda karena middleware belum berjalan.

Untuk informasi latar belakang lebih lanjut, baca juga tanggapan Taylor .

Solusi

Jika Anda masih ingin menggunakan ini, Anda dapat membuat middleware secara dinamis dan menjalankannya di konstruktor, seperti yang dijelaskan dalam panduan peningkatan:

Sebagai alternatif, Anda dapat menentukan middleware berbasis Penutupan secara langsung di konstruktor pengontrol Anda. Sebelum menggunakan fitur ini, pastikan bahwa aplikasi Anda menjalankan Laravel 5.3.4 atau lebih tinggi:

<?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);
        });
    }
}
Daan
sumber
1
Terima kasih telah menjelaskan poin __constructor (). Menghapus konsep saya.
Ashish Choudhary
16

Laravel [5.4]

Solusi saya adalah menggunakan pembantu sesi global: sesi ()

Fungsinya sedikit lebih sulit daripada $ request-> session () .

menulis :

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

mendorong :

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

mengambil :

session('key');
izzaki
sumber
Ini tidak berfungsi ketika kita menulis variabel sesi di pengontrol dan menggunakan di pengontrol lain :(
Kamlesh
4

Dalam kasus saya, saya menambahkan 4 baris berikut ke $ middlewareGroups (di app / 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',
],

PENTING: 4 baris baru harus ditambahkan SEBELUM 'throttle' dan 'bindings'!

Jika tidak, kesalahan "Token CSRF tidak cocok" akan muncul. Saya telah berjuang dalam hal ini selama beberapa jam hanya untuk menemukan urutan itu penting.

Ini memungkinkan saya untuk mengakses sesi di API saya. Saya juga menambahkan VerifyCsrfToken karena ketika cookie / sesi terlibat, CSRF perlu dijaga.

莊育銘
sumber
Jika Anda menulis apis dengan laravel ini adalah jawaban yang Anda cari :) atau tambahkan -> stateless () -> redirect ()
Bobby Axe
2

Apakah Anda dapat menggunakan ->stateless()sebelum ->redirect(). Maka Anda tidak perlu sesi lagi.

Henrique Duarte
sumber
0

dalam kasus saya itu hanya untuk mengembalikan; di akhir fungsi di mana saya telah mengatur sesi

Shawinder Jit Singh
sumber
0

Jika Anda menggunakan CSRF, masukkan 'before'=>'csrf'

Dalam kasus Anda Route::get('auth/login', ['before'=>'csrf','uses' => 'Auth\AuthController@getLogin', 'as' => 'login']);

Untuk lebih jelasnya lihat Laravel 5 Documentation Security Protecting Routes

Missaka Iddamalgoda
sumber
0

Tidak ada dalam dokumentasi laravel, saya sudah satu jam untuk mencapai ini:

Sesi saya tidak bertahan sampai saya menggunakan metode "simpan" ...

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

Grup middleware web Laravel 5.3+ secara otomatis diterapkan ke file routes / web.php Anda oleh RouteServiceProvider.

Kecuali Anda memodifikasi larik kernel $ middlewareGroups dalam urutan yang tidak didukung, mungkin Anda mencoba memasukkan permintaan sebagai ketergantungan reguler dari konstruktor.

Gunakan permintaan sebagai

public function show(Request $request){

}

dari pada

public function __construct(Request $request){

}
Kanchana Randika
sumber
0

Saya mendapatkan kesalahan ini dengan Laravel Sanctum. Saya memperbaikinya dengan menambahkan \Illuminate\Session\Middleware\StartSession::class,ke apigrup middleware di Kernel.php, tetapi saya kemudian menemukan bahwa ini "berfungsi" karena rute otentikasi saya ditambahkan api.phpsebagai ganti web.php, jadi Laravel menggunakan penjaga auth yang salah.

Saya memindahkan rute ini ke sini web.phpdan kemudian mereka mulai bekerja dengan benar dengan AuthenticatesUsers.phpsifat:

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');

Saya menemukan masalah setelah saya mendapat kesalahan aneh lainnya tentang RequestGuard::logout()tidak ada.

Itu membuat saya menyadari bahwa rute autentikasi khusus saya memanggil metode dari sifat AuthenticatesUsers, tetapi saya tidak menggunakannya Auth::routes()untuk mencapainya. Kemudian saya menyadari Laravel menggunakan penjaga web secara default dan itu berarti rute harus masuk routes/web.php.

Seperti inilah pengaturan saya sekarang dengan Sanctum dan aplikasi Vue SPA yang terpisah:

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',
    ],
];

Catatan: Dengan Laravel Sanctum dan Vue SPA domain yang sama, Anda menggunakan cookie httpOnly untuk cookie sesi, dan ingat saya cookie, dan cookie tidak aman untuk CSRF, jadi Anda menggunakan webpenjaga untuk auth, dan setiap rute yang dilindungi lainnya, JSON-return harus menggunakan auth:sanctummiddleware.

config / auth.php

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

...

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

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

Maka Anda dapat memiliki unit test seperti ini, di mana kritis, Auth::check(), Auth::user(), dan Auth::logout()bekerja seperti yang diharapkan dengan konfigurasi minimal dan penggunaan maksimal AuthenticatesUsersdan RegistersUserssifat.

Berikut adalah beberapa pengujian unit login saya:

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', '[email protected]');

    if ($user) {
        return $user;
    }

    // User::generate() is just a wrapper around User::create()
    $user = User::generate('Test User', '[email protected]', 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();
}

Saya mengganti registereddan authenticatedmetode dalam sifat autentikasi Laravel sehingga mereka mengembalikan objek pengguna, bukan hanya 204 OPTIONS:

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

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

Lihat kode vendor untuk mengetahui ciri-ciri autentikasi. Anda dapat menggunakannya tanpa tersentuh, ditambah dua metode di atas.

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

Berikut adalah tindakan Vuex Vue SPA saya untuk login:

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}.`);
    }
},

Saya membutuhkan waktu lebih dari seminggu untuk mendapatkan tes unit autentikasi Laravel Sanctum + Vue SPA + domain yang sama semuanya bekerja sesuai standar saya, jadi semoga jawaban saya di sini dapat membantu menghemat waktu orang lain di masa mendatang.

agm1984
sumber