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

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

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

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

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.


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

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

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.


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.


0

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


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


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

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){

}

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

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.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.