Laravel - Sitzungsspeicher nicht auf Anfrage festgelegt

112

Ich habe kürzlich ein neues Laravel-Projekt erstellt und bin dem Leitfaden zur Authentifizierung gefolgt. Wenn ich entweder meine Login- oder Registrierungsroute besuche, wird folgende Fehlermeldung angezeigt:

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

Ich habe keine Laravel-Kerndateien bearbeitet, sondern nur die Ansichten erstellt und die Routen zu meiner Datei route.php hinzugefügt

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

Ich habe nicht viel Erfahrung mit Laravel, bitte entschuldigen Sie meine Unwissenheit. Ich bin mir bewusst, dass es eine andere Frage gibt , die dasselbe stellt, aber keine der Antworten scheint für mich zu funktionieren. Danke fürs Lesen!

Bearbeiten:

Hier ist meine register.blade.php wie gewünscht.

@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
quelle
post register.blade.php code
Chaudhry Waqas
Sie können auch die oben genannten Routen.php durch nurRoute::controllers([ 'auth' => 'Auth\AuthController', 'password' => 'Auth\PasswordController', ]);
Chaudhry Waqas
und Sie haben Routen mit dem gleichen Namen, es ist falsch, sie sollten unterschiedliche Namen haben
xAoc
@Adamnick Gepostet und werde versuchen, es zu ersetzen.
Mattrick
Wie ist die Konfiguration Ihres Sitzungstreibers festgelegt?
Kipzes

Antworten:

160

Sie müssen die Web-Middleware verwenden, wenn Sie Sitzungsstatus, CSRF-Schutz und mehr benötigen.

Route::group(['middleware' => ['web']], function () {
    // your routes here
});
Cas Bloem
quelle
2
Ich habe das tatsächlich, ich habe nur die relevanten Routen aufgenommen.
Mattrick
Ah, ich verstehe, was du jetzt meinst. Ich habe die Routen nach innen verschoben und es hat funktioniert. Ich danke dir sehr!
Mattrick
@mattrick: hi metrix erhält den gleichen Fehler. Kannst du erklären, wohin du Routen innerhalb der Middleware verschoben hast, aber es wird der Fehler "Kein unterstützter Verschlüsseler gefunden. Die Verschlüsselung" angezeigt.
Vipin Singh
1
@ErVipinSingh Sie müssen in Ihrer App-Konfiguration einen 32-stelligen Schlüssel festlegen. Oder verwenden Siephp artisan key:generate
Cas Bloem
2
Was ist, wenn sich Ihre Anmelderoute in der API befindet?
Jay Bienvenu
56

Wenn das Hinzufügen Ihres routesInside the web middlewareaus irgendeinem Grund nicht funktioniert, versuchen Sie, dies $middlewarein hinzuzufügenKernel.php

protected $middleware = [
        //...
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
];
Waiyl Karim
quelle
4
Verdammt, das hat bei mir funktioniert, aber ich bin nicht glücklich, dass es eine "Lösung" ist, keine Lösung. Danke trotzdem!
Rav
1
Das hat es für mich behoben. Vielen Dank, dass Sie @Waiyi
Josh
1
Ihre Lösung behebt mein Problem @Waiyl_Karim
Bipul Roy
Das hat bei mir funktioniert. Ich verwende ein Reaktions-Frontend, sodass die Routengruppe nicht funktioniert, da ich den Reaktions-Router für Routen verwende.
Techcyclist
44

In meinem Fall (unter Verwendung von Laravel 5.3) konnte ich durch Hinzufügen der folgenden 2 Middleware auf Sitzungsdaten in meinen API-Routen zugreifen:

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

Ganze Deklaration ( $middlewareGroupsin Kernel.php):

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

Wenn die Antwort von Cas Bloem nicht zutrifft (dh Sie haben definitiv die webMiddleware auf der entsprechenden Route), möchten Sie möglicherweise die Reihenfolge der Middleware in Ihrem HTTP-Kernel überprüfen.

Die Standardreihenfolge Kernel.phplautet wie folgt:

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

Beachten Sie, dass danach VerifyCsrfTokenkommt StartSession. Wenn Sie diese in einer anderen Reihenfolge haben, kann die Abhängigkeit zwischen ihnen auch zur Session store not set on request.Ausnahme führen.

Hugh Grigg 葛 修 远
quelle
Ich habe es genau so. Ich bekomme immer noch die Nachricht. Ich habe auch versucht, StartSession und ShareErrorsFromSession in das $ Middleware-Array aufzunehmen. Storate / Frameword ist ebenfalls beschreibbar. (Ich benutze Wampserver 3 übrigens.)
Meddie
benutze 'Middleware' => ['Web', 'youanother.log'],
Kamaro Lambert
3
Ja! Ich war dumm und dachte, ich würde diese alphabetisch neu ordnen (weil OCD) und das hat die App kaputt gemacht. Leider habe ich erst am nächsten Tag getestet, weshalb ich hier gelandet bin. Nur für den Datensatz lautet die Standardreihenfolge für die Middleware-Gruppe "Web" in 5.3: EncryptCookies, AddQueuedCookiesToResponse, StartSession, ShareErrorsFromSession, SubstituteBindings, VerifyCsrfToken.
Ixalmida
19

Ein Problem kann sein, dass Sie versuchen, innerhalb der __constructor()Funktion Ihres Controllers auf Ihre Sitzung zuzugreifen .

Ab Laravel 5.3+ ist dies nicht mehr möglich, da es ohnehin nicht funktionieren soll, wie im Upgrade-Handbuch angegeben .

In früheren Versionen von Laravel konnten Sie auf Sitzungsvariablen oder den authentifizierten Benutzer im Konstruktor Ihres Controllers zugreifen. Dies sollte niemals ein explizites Merkmal des Frameworks sein. In Laravel 5.3 können Sie im Konstruktor Ihres Controllers nicht auf die Sitzung oder den authentifizierten Benutzer zugreifen, da die Middleware noch nicht ausgeführt wurde.

Für weitere Hintergrundinformationen lesen Sie auch Taylor seine Antwort.

Problemumgehung

Wenn Sie dies weiterhin verwenden möchten, können Sie dynamisch eine Middleware erstellen und im Konstruktor ausführen, wie im Upgrade-Handbuch beschrieben:

Alternativ können Sie eine Closure-basierte Middleware direkt im Konstruktor Ihres Controllers definieren. Stellen Sie vor Verwendung dieser Funktion sicher, dass auf Ihrer Anwendung Laravel 5.3.4 oder höher ausgeführt wird:

<?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
quelle
1
Vielen Dank, dass Sie den Punkt __constructor () erklärt haben. Klärte meine Konzepte.
Ashish Choudhary
16

Laravel [5.4]

Meine Lösung bestand darin, den globalen Sitzungshelfer zu verwenden: session ()

Seine Funktionalität ist etwas schwieriger als $ request-> session () .

Schreiben :

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

Drücken :

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

Abrufen :

session('key');
Izzaki
quelle
Dies funktioniert nicht, wenn wir Sitzungsvariable in einen Controller schreiben und in einem anderen Controller verwenden :(
Kamlesh
3

In meinem Fall habe ich $ middlewareGroups (in app / Http / Kernel.php) die folgenden 4 Zeilen hinzugefügt:

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

WICHTIG: Die 4 neuen Zeilen müssen VOR "Gas" und "Bindungen" hinzugefügt werden!

Andernfalls tritt der Fehler "CSRF-Token stimmt nicht überein" auf. Ich habe mehrere Stunden damit zu kämpfen, nur um herauszufinden, dass die Reihenfolge wichtig ist.

Dadurch konnte ich auf die Sitzung in meiner API zugreifen. Ich habe auch VerifyCsrfToken hinzugefügt, da bei Cookies / Sitzungen für CSRF gesorgt werden muss.

莊育銘
quelle
Wenn Sie Apis mit Laravel schreiben, ist dies die Antwort, nach der Sie suchen :) oder fügen Sie hinzu -> stateless () -> redirect ()
Bobby Axe
2

Können Sie ->stateless()vor dem verwenden ->redirect(). Dann brauchen Sie die Sitzung nicht mehr.

Henrique Duarte
quelle
0

in meinem Fall war es nur um die Rückkehr zu setzen; am Ende der Funktion, wo ich Sitzung eingestellt habe

Shawinder Jit Singh
quelle
0

Wenn Sie CSRF verwenden, geben Sie ein 'before'=>'csrf'

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

Weitere Informationen finden Sie in Laravel 5 Documentation Security Protecting Routes

Missaka Iddamalgoda
quelle
0

Es steht nicht in der Laravel-Dokumentation, ich habe eine Stunde gebraucht, um dies zu erreichen:

Meine Sitzung dauerte nicht an, bis ich die "Speichern" -Methode verwendete ...

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

Die Web-Middleware-Gruppe Laravel 5.3+ wird vom RouteServiceProvider automatisch auf Ihre Datei route / web.php angewendet.

Sofern Sie das Kernel $ middlewareGroups-Array nicht in einer nicht unterstützten Reihenfolge ändern, versuchen Sie wahrscheinlich, Anforderungen als reguläre Abhängigkeit vom Konstruktor einzufügen.

Anfrage verwenden als

public function show(Request $request){

}

anstatt

public function __construct(Request $request){

}
Kanchana Randika
quelle
0

Ich habe diesen Fehler mit Laravel Sanctum bekommen. Ich habe es behoben, indem ich es \Illuminate\Session\Middleware\StartSession::class,zur apiMiddleware-Gruppe in Kernel.php hinzugefügt habe, aber ich habe später herausgefunden, dass dies "funktioniert" hat, weil meine Authentifizierungsrouten api.phpanstelle von hinzugefügt wurden web.php, sodass Laravel den falschen Authentifizierungsschutz verwendete .

Ich habe diese Routen hierher verschoben web.phpund dann haben sie angefangen, richtig mit dem AuthenticatesUsers.phpMerkmal zu arbeiten:

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

Ich habe das Problem herausgefunden, nachdem ich einen weiteren seltsamen Fehler erhalten habe, über den RequestGuard::logout()es keinen gibt.

Mir wurde klar, dass meine benutzerdefinierten Authentifizierungsrouten Methoden aus dem Merkmal AuthenticatesUsers aufrufen, aber ich habe sie nicht verwendet Auth::routes(), um dies zu erreichen. Dann wurde mir klar, dass Laravel standardmäßig den Web Guard verwendet und das bedeutet, dass Routen vorhanden sein sollten routes/web.php.

So sehen meine Einstellungen jetzt mit Sanctum und einer entkoppelten Vue SPA-App aus:

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

Hinweis: Mit Laravel Sanctum und Vue SPA mit derselben Domain verwenden Sie httpOnly-Cookies für Sitzungscookies und erinnern mich an Cookies und unsichere Cookies für CSRF. Daher verwenden Sie den webGuard für die Authentifizierung und jede andere geschützte JSON-Rückgaberoute auth:sanctumMiddleware.

config / auth.php

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

...

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

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

Dann können Sie Unit-Tests wie diesen durchführen lassen, wo dies kritisch ist Auth::check(), Auth::user()und Auth::logout()wie erwartet mit minimaler Konfiguration und maximaler Verwendung von AuthenticatesUsersund RegistersUsersMerkmalen arbeiten.

Hier sind einige meiner Login-Unit-Tests:

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

Ich habe die Methoden registeredund authenticatedin den Laravel-Authentifizierungsmerkmalen überschrieben , sodass sie das Benutzerobjekt anstelle nur der 204 OPTIONEN zurückgeben:

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

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

Sehen Sie sich den Herstellercode für die Authentifizierungsmerkmale an. Sie können sie unberührt verwenden, plus diese beiden oben genannten Methoden.

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

Hier sind die Vuex-Aktionen meines Vue SPA für die Anmeldung:

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

Ich habe über eine Woche gebraucht, um Laravel Sanctum + Vue SPA + Auth-Unit-Tests mit derselben Domäne zu erhalten, die alle meinem Standard entsprechen. Hoffentlich kann meine Antwort hier dazu beitragen, anderen in Zukunft Zeit zu sparen.

agm1984
quelle