Laravel - Magasin de session non défini sur demande

114

J'ai récemment créé un nouveau projet Laravel et suivais le guide sur l'authentification. Lorsque je visite mon itinéraire de connexion ou d'inscription, j'obtiens l'erreur suivante:

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

Je n'ai modifié aucun fichier Laravel de base, j'ai seulement créé les vues et ajouté les routes à mon fichier 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']);

Je n'ai pas beaucoup d'expérience avec Laravel, alors excusez mon ignorance. Je suis conscient qu'il y a une autre question qui pose la même chose, mais aucune des réponses ne semble fonctionner pour moi. Merci d'avoir lu!

Éditer:

Voici mon register.blade.php comme demandé.

@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
la source
post register.blade.php code
Chaudhry Waqas
vous pouvez également remplacer les routes.php ci-dessus par justeRoute::controllers([ 'auth' => 'Auth\AuthController', 'password' => 'Auth\PasswordController', ]);
Chaudhry Waqas
et vous avez des routes avec le même nom, c'est faux, elles devraient avoir des noms différents
xAoc
@Adamnick Publié et essaiera de le remplacer.
mattrick
Comment la configuration de votre pilote de session est-elle définie?
kipzes

Réponses:

165

Vous devrez utiliser le middleware Web si vous avez besoin d'un état de session, d'une protection CSRF, etc.

Route::group(['middleware' => ['web']], function () {
    // your routes here
});
Cas Bloem
la source
2
Je l'ai en fait, j'incluais simplement les itinéraires pertinents.
mattrick
Ah je vois ce que tu veux dire maintenant, j'ai déplacé les itinéraires à l'intérieur et ça a marché. Merci beaucoup!
mattrick
@mattrick: salut metrix obtient la même erreur. Pouvez-vous expliquer où vous avez déplacé les routes à l'intérieur du middleware, mais il affiche l'erreur "Aucun chiffrement pris en charge trouvé. Le chiffrement".
Vipin Singh
1
@ErVipinSingh vous devrez définir une clé de 32 caractères dans la configuration de votre application. Ou utilisezphp artisan key:generate
Cas Bloem
2
Et si votre itinéraire de connexion se trouve dans l'API?
Jay Bienvenu
56

Si vous ajoutez votre routesintérieur du web middlewarene fonctionne pas pour une raison quelconque , essayez d' ajouter ceci à $middlewareenKernel.php

protected $middleware = [
        //...
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
];
Waiyl Karim
la source
4
Merde, cela a fonctionné pour moi, mais je ne suis pas content que ce soit un "correctif", pas une solution. Merci quand même!
Rav
1
Cela a réglé le problème pour moi. Merci @Waiyi
Josh
1
Votre solution résout mon problème @Waiyl_Karim
Bipul Roy
Cela a fonctionné pour moi. J'utilise une interface de réaction pour que le groupe de routes ne fonctionne pas car j'utilise un routeur de réaction pour les routes.
techcyclist
44

Dans mon cas (en utilisant Laravel 5.3), l'ajout uniquement des 2 middlewares suivants m'a permis d'accéder aux données de session dans mes routes API:

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

Déclaration complète ( $middlewareGroupsdans Kernel.php):

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

Si la réponse de Cas Bloem ne s'applique pas (c'est-à-dire que vous avez définitivement le webmiddleware sur la route applicable), vous voudrez peut-être vérifier l'ordre des middlewares dans votre noyau HTTP.

L'ordre par défaut Kernel.phpest le suivant:

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

Notez que VerifyCsrfTokenvient après StartSession. Si vous les avez dans un ordre différent, la dépendance entre eux peut également conduire à l' Session store not set on request.exception.

Hugh Grigg 葛 修 远
la source
je l'ai exactement comme ça. Je reçois toujours le message. J'ai également essayé de mettre StartSession et ShareErrorsFromSession dans le tableau middleware $. Storate / frameword est également accessible en écriture. (J'utilise Wampserver 3 btw.)
Meddie
use 'middleware' => ['web', 'youanother.log'],
Kamaro Lambert
3
Oui! J'étais stupide et j'ai pensé que je les réorganiserais par ordre alphabétique (parce que le TOC) et cela a cassé l'application. Malheureusement, je n'ai testé que le lendemain, c'est pourquoi je me suis retrouvé ici. Pour mémoire, l'ordre par défaut pour le groupe middleware "web" dans 5.3 est: EncryptCookies, AddQueuedCookiesToResponse, StartSession, ShareErrorsFromSession, SubstituteBindings, VerifyCsrfToken.
Ixalmida
19

Un problème peut être que vous essayez d' accéder à votre session à l'intérieur de la __constructor()fonction de votre contrôleur .

À partir de Laravel 5.3+, cela n'est plus possible car il n'est pas prévu de fonctionner de toute façon, comme indiqué dans le guide de mise à niveau .

Dans les versions précédentes de Laravel, vous pouviez accéder aux variables de session ou à l'utilisateur authentifié dans le constructeur de votre contrôleur. Cela n'a jamais été destiné à être une caractéristique explicite du cadre. Dans Laravel 5.3, vous ne pouvez pas accéder à la session ou à l'utilisateur authentifié dans le constructeur de votre contrôleur car le middleware n'est pas encore exécuté.

Pour plus d'informations, lisez également sa réponse de Taylor .

solution de contournement

Si vous souhaitez toujours l'utiliser, vous pouvez créer dynamiquement un middleware et l'exécuter dans le constructeur, comme décrit dans le guide de mise à niveau:

Comme alternative, vous pouvez définir un middleware basé sur Closure directement dans le constructeur de votre contrôleur. Avant d'utiliser cette fonctionnalité, assurez-vous que votre application exécute Laravel 5.3.4 ou supérieur:

<?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
la source
1
Merci d'avoir expliqué le point __constructor (). Effacé mes concepts.
Ashish Choudhary
16

Laravel [5.4]

Ma solution était d'utiliser l'assistant de session global: session ()

Sa fonctionnalité est un peu plus difficile que $ request-> session () .

écriture :

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

poussant :

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

récupération :

session('key');
izzaki
la source
Cela ne fonctionne pas lorsque nous écrivons une variable de session dans un contrôleur et que nous l'utilisons dans un autre contrôleur :(
Kamlesh
4

Dans mon cas, j'ai ajouté les 4 lignes suivantes à $ middlewareGroups (dans 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',
],

IMPORTANT: Les 4 nouvelles lignes doivent être ajoutées AVANT 'throttle' et 'bindings'!

Sinon, une erreur "jeton CSRF ne correspond pas" se produira. J'ai lutté pendant plusieurs heures pour trouver que l'ordre est important.

Cela m'a permis d'accéder à la session dans mon API. J'ai également ajouté VerifyCsrfToken car lorsque des cookies / sessions sont impliqués, CSRF doit être pris en charge.

莊育銘
la source
Si vous écrivez des apis avec laravel, c'est la réponse que vous cherchez :) ou ajoutez -> stateless () -> redirect ()
Bobby Axe
2

Pouvez-vous utiliser ->stateless()avant le ->redirect(). Ensuite, vous n'avez plus besoin de la session.

Henrique Duarte
la source
0

dans mon cas c'était juste pour mettre retour; à la fin de la fonction où j'ai défini la session

Shawinder Jit Singh
la source
0

Si vous utilisez CSRF, entrez 'before'=>'csrf'

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

Pour plus de détails, consultez la documentation Laravel 5 Security Protecting Routes

Missaka Iddamalgoda
la source
0

Ce n'est pas sur la documentation de laravel, j'ai mis une heure pour y parvenir:

Ma session n'a pas persisté jusqu'à ce que j'utilise la méthode "save" ...

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

Le groupe middleware Web Laravel 5.3+ est automatiquement appliqué à votre fichier routes / web.php par RouteServiceProvider.

Sauf si vous modifiez le tableau kernel $ middlewareGroups dans un ordre non pris en charge, vous essayez probablement d'injecter des requêtes en tant que dépendance régulière du constructeur.

Utiliser la demande comme

public function show(Request $request){

}

au lieu de

public function __construct(Request $request){

}
Kanchana Randika
la source
0

J'obtenais cette erreur avec Laravel Sanctum. Je l'ai corrigé en ajoutant \Illuminate\Session\Middleware\StartSession::class,au apigroupe middleware dans Kernel.php, mais j'ai compris plus tard que cela "fonctionnait" parce que mes routes d'authentification étaient ajoutées au api.phplieu deweb.php , donc Laravel utilisait le mauvais garde d'authentification.

J'ai déplacé ces itinéraires ici web.php, puis ils ont commencé à fonctionner correctement avec le AuthenticatesUsers.phptrait:

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

J'ai compris le problème après avoir reçu une autre erreur étrange à propos de RequestGuard::logout()n'existe pas.

Cela m'a fait réaliser que mes routes d'authentification personnalisées appelaient des méthodes du trait AuthenticatesUsers, mais je ne les utilisais pas Auth::routes()pour l'accomplir. Ensuite, j'ai réalisé que Laravel utilise la protection Web par défaut et que cela signifie que les routes doivent être incluses routes/web.php.

Voici à quoi ressemblent mes paramètres maintenant avec Sanctum et une application Vue SPA découplée:

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

Remarque: avec Laravel Sanctum et Vue SPA du même domaine, vous utilisez les cookies httpOnly pour le cookie de session, et vous souvenez-moi du cookie et du cookie non sécurisé pour CSRF, vous utilisez donc le webguard pour l'authentification, et toute autre route protégée de retour JSON doit utiliser auth:sanctummiddleware.

config / auth.php

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

...

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

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

Ensuite , vous pouvez avoir des tests unitaires tels que celui -ci où la critique, Auth::check(), Auth::user()et Auth::logout()fonctionnent comme prévu avec config minimale et l' utilisation maximale de AuthenticatesUserset RegistersUserstraits.

Voici quelques-uns de mes tests unitaires de connexion:

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

J'ai remplacé les méthodes registeredet authenticateddans les traits d'authentification Laravel afin qu'elles renvoient l'objet utilisateur au lieu des 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,
    ]);
}

Regardez le code du fournisseur pour les traits d'authentification. Vous pouvez les utiliser tels quels, ainsi que les deux méthodes ci-dessus.

  • vendeur / laravel / ui / auth-backend / RegistersUsers.php
  • fournisseur / laravel / ui / auth-backend / AuthenticatesUsers.php

Voici les actions Vuex de mon Vue SPA pour la connexion:

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

Il m'a fallu plus d'une semaine pour que les tests unitaires d'authentification de Laravel Sanctum + Vue SPA + dans le même domaine fonctionnent tous selon mes normes, alors j'espère que ma réponse ici pourra aider d'autres personnes à gagner du temps à l'avenir.

agm1984
la source