Laravel - Archivio sessioni non impostato su richiesta


113

Di recente ho creato un nuovo progetto Laravel e stavo seguendo la guida sull'autenticazione. Quando visito il mio percorso di accesso o registro, ottengo il seguente errore:

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

Non ho modificato alcun file Laravel di base, ho solo creato le viste e aggiunto le rotte al mio file routes.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']);

Non ho molta esperienza con Laravel, quindi scusa la mia ignoranza. Sono consapevole che c'è un'altra domanda che fa la stessa cosa, ma nessuna delle risposte sembra funzionare per me. Grazie per aver letto!

Modificare:

Ecco il mio register.blade.php come richiesto.

@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

post register.blade.php code
Chaudhry Waqas

puoi anche sostituire il route.php sopra con soloRoute::controllers([ 'auth' => 'Auth\AuthController', 'password' => 'Auth\PasswordController', ]);
Chaudhry Waqas

e hai rotte con lo stesso nome, è sbagliato, dovrebbero avere nomi diversi
xAoc

@Adamnick Posted e proverò a sostituirlo.
mattrick

Come viene impostata la configurazione del driver di sessione?
kipzes

Risposte:


163

Dovrai utilizzare il middleware web se hai bisogno dello stato della sessione, della protezione CSRF e altro ancora.

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

2
In realtà ce l'ho, stavo solo includendo i percorsi rilevanti.
mattrick

Ah capisco cosa intendi adesso, ho spostato le vie all'interno e ha funzionato. Grazie mille!
mattrick

@mattrick: hi metrix ottenendo lo stesso errore. Puoi spiegare dove hai spostato le rotte all'interno del middleware ma mostra l'errore "Nessun cifratore supportato trovato. Il cifrario".
Vipin Singh

1
@ErVipinSingh dovrai impostare una chiave di 32 caratteri nella configurazione dell'app. Oppure usaphp artisan key:generate
Cas Bloem

2
Cosa succede se il percorso di accesso è nell'API?
Jay Bienvenu

56

Se l'aggiunta del tuo routesinterno a web middlewarenon funziona per qualsiasi motivo, prova ad aggiungerlo a $middlewareinKernel.php

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

4
Dannazione, questo ha funzionato per me, ma non sono contento che sia una "soluzione", non una soluzione. Grazie comunque!
Rav

1
Questo ha risolto il problema per me. Grazie @Waiyi
Josh

1
La tua soluzione risolve il mio problema @Waiyl_Karim
Bipul Roy

Questo ha funzionato per me. Sto usando un frontend di reazione, quindi il gruppo di rotte non funziona mentre sto usando il router di reazione per le rotte.
ciclista tecnico

44

Nel mio caso (utilizzando Laravel 5.3) l'aggiunta solo del seguente middleware 2 mi ha permesso di accedere ai dati della sessione nelle mie rotte API:

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

Dichiarazione completa ( $middlewareGroupsin Kernel.php):

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

21

Se la risposta di Cas Bloem non si applica (cioè hai sicuramente il webmiddleware sulla route applicabile), potresti voler controllare l'ordine dei middleware nel tuo kernel HTTP.

L'ordine predefinito in Kernel.phpè questo:

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

Nota che VerifyCsrfTokenviene dopo StartSession. Se li hai in un ordine diverso, la dipendenza tra loro può anche portare Session store not set on request.all'eccezione.


ce l'ho esattamente così. Ricevo ancora il messaggio. Ho anche provato a mettere StartSession e ShareErrorsFromSession nell'array $ middleware. Anche Storate / frameword è scrivibile. (Sto usando Wampserver 3 btw.)
Meddie

use 'middleware' => ['web', 'youanother.log'],
Kamaro Lambert,

3
Sì! Ero stupido e ho pensato di riordinare quelli in ordine alfabetico (perché OCD) e questo ha rotto l'app. Purtroppo non ho provato fino al giorno successivo, motivo per cui sono finito qui. Per la cronaca, l'ordine predefinito per il gruppo middleware "web" nella versione 5.3 è: EncryptCookies, AddQueuedCookiesToResponse, StartSession, ShareErrorsFromSession, SubstituteBindings, VerifyCsrfToken.
Ixalmida

19

Un problema può essere che si tenta di accedere alla sessione all'interno della __constructor()funzione del controller .

Da Laravel 5.3+ questo non è più possibile perché non è destinato a funzionare comunque, come indicato nella guida all'aggiornamento .

Nelle versioni precedenti di Laravel, era possibile accedere alle variabili di sessione o all'utente autenticato nel costruttore del controller. Questo non è mai stato inteso come una caratteristica esplicita del framework. In Laravel 5.3, non è possibile accedere alla sessione o all'utente autenticato nel costruttore del controller perché il middleware non è ancora stato eseguito.

Per ulteriori informazioni di base, leggi anche la sua risposta di Taylor .

Soluzione

Se vuoi ancora usarlo, puoi creare dinamicamente un middleware ed eseguirlo nel costruttore, come descritto nella guida all'aggiornamento:

In alternativa, puoi definire un middleware basato su Closure direttamente nel costruttore del controller. Prima di utilizzare questa funzione, assicurati che la tua applicazione esegua Laravel 5.3.4 o superiore:

<?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
Grazie per aver spiegato il punto __constructor (). Cancella i miei concetti.
Ashish Choudhary

16

Laravel [5.4]

La mia soluzione era usare l'helper di sessione globale: session ()

La sua funzionalità è un po 'più difficile di $ request-> session () .

scrittura :

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

spingendo :

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

recupero :

session('key');

Questo non funziona quando scriviamo una variabile di sessione in un controller e la usiamo in un altro controller :(
Kamlesh

4

Nel mio caso ho aggiunto le seguenti 4 righe a $ middlewareGroups (in 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',
],

IMPORTANTE: le 4 nuove linee devono essere aggiunte PRIMA di "acceleratore" e "attacchi"!

In caso contrario, verrà generato un errore "Token CSRF non corrispondente". Ho lottato per diverse ore solo per scoprire che l'ordine è importante.

Questo mi ha permesso di accedere alla sessione nella mia API. Ho anche aggiunto VerifyCsrfToken poiché quando sono coinvolti cookie / sessioni, è necessario prendersi cura di CSRF.


Se stai scrivendo api con laravel questa è la risposta che stai cercando :) o aggiungi -> stateless () -> redirect ()
Bobby Axe

2

Puoi usare ->stateless() prima del file ->redirect(). Allora non hai più bisogno della sessione.


0

nel mio caso era solo per mettere ritorno; alla fine della funzione in cui ho impostato la sessione


0

Se stai usando CSRF, inserisci 'before'=>'csrf'

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

Per maggiori dettagli vedi Laravel 5 Documentation Security Protecting Routes


0

Non è sulla documentazione di laravel, sono stata un'ora per ottenere questo:

La mia sessione non è durata fino a quando non ho utilizzato il metodo "salva" ...

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

0

Il gruppo middleware web Laravel 5.3+ viene applicato automaticamente al file route / web.php dal RouteServiceProvider.

A meno che non modifichi l'array $ middlewareGroups del kernel in un ordine non supportato, probabilmente stai tentando di iniettare richieste come una normale dipendenza dal costruttore.

Usa richiesta come

public function show(Request $request){

}

invece di

public function __construct(Request $request){

}

0

Ho ricevuto questo errore con Laravel Sanctum. L'ho risolto aggiungendo \Illuminate\Session\Middleware\StartSession::class,al apigruppo middleware in Kernel.php, ma in seguito ho capito che "funzionava" perché le mie rotte di autenticazione sono state aggiunte api.phpinvece diweb.php , quindi Laravel stava usando la protezione di autenticazione sbagliata.

Ho spostato questi percorsi qui dentro web.phpe poi hanno iniziato a lavorare correttamente con il AuthenticatesUsers.phptratto:

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

Ho scoperto il problema dopo aver ricevuto un altro strano errore RequestGuard::logout() non esiste.

Mi ha fatto capire che le mie route di autenticazione personalizzate chiamano metodi dal tratto AuthenticatesUsers, ma non stavo usando Auth::routes()per realizzarlo. Poi ho capito che Laravel usa il web guard per impostazione predefinita e questo significa che le rotte dovrebbero essere inroutes/web.php .

Ecco come appaiono le mie impostazioni ora con Sanctum e un'app Vue SPA disaccoppiata:

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

Nota: con Laravel Sanctum e Vue SPA dello stesso dominio, utilizzi solo i cookie httpOnly per il cookie di sessione e il cookie ricordami e il cookie non sicuro per CSRF, quindi utilizzi la webprotezione per l'autenticazione e ogni altro percorso protetto di ritorno JSON dovrebbe utilizzare auth:sanctummiddleware.

config / auth.php

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

...

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

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

Allora si può avere unit test come questo, in cui critica, Auth::check(), Auth::user(), e Auth::logout()il lavoro come previsto con configurazione minima e massima di utilizzo AuthenticatesUserseRegistersUsers caratteristiche.

Ecco un paio di miei unit test di accesso:

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();
}

Ho sovrascritto i metodi registerede authenticatednei tratti di autenticazione Laravel in modo che restituiscano l'oggetto utente anziché solo le 204 OPZIONI:

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

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

Guarda il codice del fornitore per i tratti di autenticazione. Puoi usarli intatti, oltre a questi due metodi sopra.

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

Ecco le azioni Vuex della mia Vue SPA per l'accesso:

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

Mi ci è voluta più di una settimana per ottenere Laravel Sanctum + Vue SPA nello stesso dominio + test delle unità di autenticazione che funzionassero tutti secondo i miei standard, quindi spero che la mia risposta qui possa aiutare a risparmiare tempo ad altri in futuro.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.