Laravel: la tienda de sesiones no se configura a pedido

113

Recientemente creé un nuevo proyecto de Laravel y seguí la guía sobre autenticación. Cuando visito mi ruta de inicio de sesión o registro, aparece el siguiente error:

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

No he editado ningún archivo principal de Laravel, solo he creado las vistas y agregué las rutas a mi archivo 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']);

No tengo mucha experiencia con Laravel, así que disculpe mi ignorancia. Soy consciente de que hay otra pregunta que hace lo mismo, pero ninguna de las respuestas parece funcionar para mí. ¡Gracias por leer!

Editar:

Aquí está mi register.blade.php según lo solicitado.

@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
fuente
publicar el código register.blade.php
Chaudhry Waqas
también puede reemplazar las rutas anteriores.php con soloRoute::controllers([ 'auth' => 'Auth\AuthController', 'password' => 'Auth\PasswordController', ]);
Chaudhry Waqas
y tiene rutas con el mismo nombre, está mal, deberían tener nombres diferentes
xAoc
@Adamnick Publicado e intentará reemplazarlo.
mattrick
¿Cómo se establece la configuración del controlador de sesión?
kipzes

Respuestas:

163

Deberá utilizar el middleware web si necesita el estado de la sesión, la protección CSRF y más.

Route::group(['middleware' => ['web']], function () {
    // your routes here
});
Cas Bloem
fuente
2
De hecho, tengo eso, solo estaba incluyendo las rutas relevantes.
mattrick
Ah, veo lo que quieres decir ahora, moví las rutas adentro y funcionó. Muchas gracias!
mattrick
@mattrick: hola metrix obteniendo el mismo error. ¿Puede explicar dónde movió las rutas dentro del middleware pero muestra el error "No se encontró ningún cifrado compatible. El cifrado".
Vipin Singh
1
@ErVipinSingh necesitará establecer una clave de 32 caracteres en la configuración de su aplicación. O usephp artisan key:generate
Cas Bloem
2
¿Qué pasa si su ruta de inicio de sesión está en la API?
Jay Bienvenu
56

Si se añade el routesinterior de la web middlewareno funciona por algún motivo, trate de añadir esto a $middlewareenKernel.php

protected $middleware = [
        //...
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
];
Waiyl Karim
fuente
4
Maldita sea, esto me ha funcionado, pero no estoy contento de que sea una "solución", no una solución. ¡Gracias de cualquier manera!
Rav
1
Esto me lo arregló. Gracias @Waiyi
Josh
1
Tu solución soluciona mi problema @Waiyl_Karim
Bipul Roy
Esto funcionó para mí. Estoy usando una interfaz de reacción para que el grupo de rutas no funcione, ya que estoy usando el enrutador de reacción para las rutas.
techcyclist
44

En mi caso (usando Laravel 5.3), agregar solo los siguientes 2 middleware me permitió acceder a los datos de sesión en mis rutas API:

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

Declaración completa ( $middlewareGroupsen Kernel.php):

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

Si la respuesta de Cas Bloem no se aplica (es decir, definitivamente tiene el webmiddleware en la ruta aplicable), es posible que desee verificar el orden de los middlewares en su kernel HTTP.

El orden predeterminado Kernel.phpes este:

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

Tenga en cuenta que VerifyCsrfTokenviene después StartSession. Si los tiene en un orden diferente, la dependencia entre ellos también puede conducir a la Session store not set on request.excepción.

Hugh Grigg 葛 修 远
fuente
lo tengo exactamente así. sigo recibiendo el mensaje. También intenté poner StartSession y ShareErrorsFromSession en la matriz $ middleware. Storate / frameword también se puede escribir. (Estoy usando Wampserver 3 por cierto)
Meddie
use 'middleware' => ['web', 'youanother.log'],
Kamaro Lambert
3
¡Sí! Fui tonto y pensé en reordenarlos alfabéticamente (porque TOC) y eso rompió la aplicación. Desafortunadamente, no probé hasta el día siguiente, por eso terminé aquí. Solo para que conste, el orden predeterminado para el grupo de middleware "web" en 5.3 es: EncryptCookies, AddQueuedCookiesToResponse, StartSession, ShareErrorsFromSession, SubstituteBindings, VerifyCsrfToken.
Ixalmida
19

Un problema puede ser que intente acceder a su sesión dentro de la __constructor()función de su controlador .

Desde Laravel 5.3+, esto ya no es posible porque no está destinado a funcionar de todos modos, como se indica en la guía de actualización .

En versiones anteriores de Laravel, podía acceder a las variables de sesión o al usuario autenticado en el constructor de su controlador. Esto nunca tuvo la intención de ser una característica explícita del marco. En Laravel 5.3, no puede acceder a la sesión o al usuario autenticado en el constructor de su controlador porque el middleware aún no se ha ejecutado.

Para obtener más información de antecedentes, lea también su respuesta de Taylor .

Solución alterna

Si aún desea usar esto, puede crear dinámicamente un middleware y ejecutarlo en el constructor, como se describe en la guía de actualización:

Como alternativa, puede definir un middleware basado en Closure directamente en el constructor de su controlador. Antes de usar esta función, asegúrese de que su aplicación esté ejecutando Laravel 5.3.4 o superior:

<?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
fuente
1
Gracias por explicar el punto __constructor (). Limpió mis conceptos.
Ashish Choudhary
16

Laravel [5.4]

Mi solución fue usar el asistente de sesión global: session ()

Su funcionalidad es un poco más difícil que $ request-> session () .

escribiendo :

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

empujando :

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

recuperando :

session('key');
izzaki
fuente
Esto no funciona cuando escribimos la variable de sesión en un controlador y la usamos en otro controlador :(
Kamlesh
4

En mi caso, agregué las siguientes 4 líneas a $ middlewareGroups (en 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: ¡Las 4 nuevas líneas deben agregarse ANTES de 'aceleración' y 'fijaciones'!

De lo contrario, aparecerá un error "El token CSRF no coincide". He luchado con esto durante varias horas solo para encontrar que el orden es importante.

Esto me permitió acceder a la sesión en mi API. También agregué VerifyCsrfToken ya que cuando hay cookies / sesiones involucradas, CSRF debe ser atendido.

莊育銘
fuente
Si está escribiendo apis con laravel, esta es la respuesta que está buscando :) o agregue -> stateless () -> redirect ()
Bobby Axe
2

¿Puede usar ->stateless()antes del ->redirect(). Entonces ya no necesitas la sesión.

Henrique Duarte
fuente
0

en mi caso fue solo para poner vuelta; al final de la función donde configuré la sesión

Shawinder Jit Singh
fuente
0

Si está usando CSRF ingrese 'before'=>'csrf'

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

Para obtener más detalles, consulte Laravel 5 Documentation Security Protecting Routes

Missaka Iddamalgoda
fuente
0

No está en la documentación de laravel, he tardado una hora en lograr esto:

Mi sesión no persistió hasta que usé el método "guardar" ...

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

El grupo de middleware web Laravel 5.3+ se aplica automáticamente a su archivo routes / web.php por RouteServiceProvider.

A menos que modifique la matriz $ middlewareGroups del kernel en un orden no admitido, probablemente esté intentando inyectar solicitudes como una dependencia regular del constructor.

Usar solicitud como

public function show(Request $request){

}

en vez de

public function __construct(Request $request){

}
Kanchana Randika
fuente
0

Recibí este error con Laravel Sanctum. Lo arreglé agregando \Illuminate\Session\Middleware\StartSession::class,al apigrupo de middleware en Kernel.php, pero luego descubrí que esto "funcionaba" porque mis rutas de autenticación se agregaron en api.phplugar deweb.php , por lo que Laravel estaba usando la protección de autenticación incorrecta.

Moví estas rutas aquí web.phpy luego comenzaron a funcionar correctamente con el AuthenticatesUsers.phprasgo:

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

Descubrí el problema después de recibir otro error extraño sobre RequestGuard::logout() no existe.

Me hizo darme cuenta de que mis rutas de autenticación personalizadas están llamando a métodos del rasgo AuthenticatesUsers, pero no estaba usando Auth::routes()para lograrlo. Luego me di cuenta de que Laravel usa la protección web de forma predeterminada y eso significa que las rutas deben estar enroutes/web.php .

Así es como se ven mis configuraciones ahora con Sanctum y una aplicación Vue SPA desacoplada:

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 y Vue SPA del mismo dominio, usa httpOnly cookies para la cookie de sesión, y recuerda la cookie y la cookie no segura para CSRF, por lo que usa la webprotección para la autenticación y todas las demás rutas protegidas de retorno de JSON deben usar auth:sanctummiddleware.

config / auth.php

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

...

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

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

A continuación, puede tener pruebas unitarias como ésta, donde críticamente, Auth::check(), Auth::user(), y Auth::logout()funciona como se espera con configuración mínima y máxima de uso AuthenticatesUsersy RegistersUserscaracterísticas.

Aquí hay un par de mis pruebas unitarias de inicio de sesión:

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

Anulé los métodos registeredy authenticateden los rasgos de autenticación de Laravel para que devuelvan el objeto de usuario en lugar de solo 204 OPCIONES:

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

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

Mire el código del proveedor para ver los rasgos de autenticación. Puede utilizarlos intactos, además de los dos métodos anteriores.

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

Aquí están las acciones de Vuex de mi Vue SPA para iniciar sesión:

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

Me tomó más de una semana conseguir que las pruebas unitarias de autenticación de Vue SPA + de Laravel Sanctum + del mismo dominio funcionaran a la altura de mi estándar, así que espero que mi respuesta aquí pueda ayudar a ahorrar tiempo a otros en el futuro.

agm1984
fuente