Laravel - 会话存储未按要求设置

时间:2015-12-24 08:42:04

标签: php laravel

我最近创建了一个新的Laravel项目,并遵循身份验证指南。当我访问我的登录或注册路由时,我收到以下错误:

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

我还没有编辑任何核心Laravel文件,我只创建了视图并将路由添加到我的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']);

我对Laravel没有多少经验,所以请原谅我的无知。我知道有another question问同样的事情,但这些答案似乎都不适合我。谢谢你的阅读!

修改

这是我的register.blade.php按要求。

@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

15 个答案:

答案 0 :(得分:125)

如果您需要会话状态,CSRF保护等,则需要使用 Web中间件

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

答案 1 :(得分:42)

如果在routes内添加web middleware因任何原因无效,请尝试将此$middleware添加到Kernel.php

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

答案 2 :(得分:35)

就我而言(使用Laravel 5.3),只添加以下2个中间件,允许我访问API路径中的会话数据:

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

整个声明(Kernel.php中的$middlewareGroups):

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

答案 3 :(得分:17)

如果Cas Bloem的答案不适用(即您确实在适用的路由上获得了web中间件),您可能需要检查HTTP内核中间件的顺序。

Kernel.php中的默认顺序是:

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

请注意,VerifyCsrfToken位于StartSession之后。如果你有不同的顺序,它们之间的依赖关系也会导致Session store not set on request.异常。

答案 4 :(得分:13)

问题可能是您尝试在控制器的__constructor()功能中访问您的会话。

从Laravel 5.3+开始,这是不可能的,因为无论如何它都无法工作,as stated in the upgrade guide

  

在早期版本的Laravel中,您可以访问会话变量或   控制器构造函数中经过身份验证的用户。这是   从来没有打算成为框架的明确特征。在Laravel   5.3,您无法访问控制器构造函数中的会话或经过身份验证的用户,因为中间件尚未运行。

有关更多背景信息,请阅读Taylor他的回复。

解决方法

如果您仍想使用它,您可以动态创建中间件并在构造函数中运行它,如升级指南中所述:

  

作为替代方案,您可以直接定义基于Closure的中间件   在你的控制器的构造函数中。在使用此功能之前,请确保   您的应用程序正在运行Laravel 5.3.4或更高版本:

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

答案 5 :(得分:11)

Laravel [5.4]

我的解决方案是使用全局会话助手: 的 会话()

它的功能比 $ request-&gt; session() 稍微难点。

<强>写

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

<强>推

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

<强>检索

session('key');

答案 6 :(得分:1)

我在Laravel Sanctum遇到了这个错误。我通过在Kernel.php的\Illuminate\Session\Middleware\StartSession::class,中间件组中添加api来解决它,但是后来我发现这是可行的,因为我的身份验证路由是在api.php中而不是{{1 }},因此Laravel使用了错误的身份验证防护。

我将这些路线移到了web.php,然后它们开始以web.php特性正常工作:

AuthenticatesUsers.php

在我发现另一个关于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'); 的奇怪错误之后,我发现了问题。

这让我意识到我的自定义身份验证路由是从AuthenticatesUsers特征调用方法,但是我没有使用RequestGuard::logout()来完成它。然后我意识到Laravel默认使用网络防护,这意味着路由应该在Auth::routes()中。

这是我现在使用Sanctum和解耦的Vue SPA应用程序时的设置:

Kernel.php

routes/web.php

注意:通过Laravel Sanctum和同域Vue SPA,您将httpOnly cookie用于会话cookie,并记住我的cookie和不安全的cookie用于CSRF,因此您使用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', ], ]; 保护身份验证,所有其他受保护的,返回JSON的路由都应使用web中间件。

config / auth.php

auth:sanctum

然后,您可以进行诸如此类的单元测试,其中'defaults' => [ 'guard' => 'web', 'passwords' => 'users', ], ... 'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], 'api' => [ 'driver' => 'token', 'provider' => 'users', 'hash' => false, ], ], Auth::check()Auth::user()可以按预期工作,并且配置最少,Auth::logout()的使用率最高,并且AuthenticatesUsers特质。

以下是我的一些登录单元测试:

TestCase.php

RegistersUsers

LoginTest.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'], []);
}

我在Laravel auth特性中重写了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(); } registered方法,以便它们返回用户对象,而不仅仅是204个选项:

authenticated

查看auth特性的供应商代码。您可以不加修改地使用它们,以及上面的两种方法。

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

这是我的Vue SPA的Vuex登录操作:

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

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

我花了一个多星期的时间来获得Laravel Sanctum +同域Vue SPA +身份验证单元测试,一切都达到了我的标准,因此希望我的回答可以帮助将来节省其他时间。

答案 7 :(得分:0)

在我的情况下,它只是放 回归; 在功能结束时我已设置会话

答案 8 :(得分:0)

如果您使用的是CSRF,请输入'before'=>'csrf'

在您的情况下 Route::get('auth/login', ['before'=>'csrf','uses' => 'Auth\AuthController@getLogin', 'as' => 'login']);

有关更多详细信息,请查看Laravel 5文档Security Protecting Routes

答案 9 :(得分:0)

您可以在->stateless()之前使用->redirect()吗? 然后,您不再需要该会话。

答案 10 :(得分:0)

在我的情况下,我在$ middlewareGroups中添加了以下4行(在app / Http / Kernel.php中):

getIsNameUnique

重要提示:必须在“油门”和“绑定”之前添加4个新行!

否则,将出现“ CSRF令牌不匹配”错误。为了找到订单很重要,我为此苦了几个小时。

这使我可以使用API​​访问会话。我还添加了VerifyCsrfToken,因为涉及cookie /会话时,需要注意CSRF。

答案 11 :(得分:0)

它不在laravel文档中,我花了一个小时才实现:

我的会话直到我使用“保存”方法后才持续...

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

答案 12 :(得分:0)

Laravel 5.3+网络中间件组由RouteServiceProvider自动应用于您的route / web.php文件。

除非您以不受支持的顺序修改内核$ middlewareGroups数组,否则您可能试图将请求作为常规依赖项从构造函数中注入。

将请求用作

public function show(Request $request){

}

代替

public function __construct(Request $request){

}

答案 13 :(得分:0)

我使用的是laravel 7.x,此问题出现了。以下解决了该问题:

转到kernel.php并将这两个类添加到受保护的$ middleware

\ Illuminate \ Session \ Middleware \ StartSession :: class, \ Illuminate \ View \ Middleware \ ShareErrorsFromSession :: class,

答案 14 :(得分:0)

在我自己的情况下(在 Laravel 5.8 中),我的 Laravel 项目中位于 session.php 目录中的 ../[mylaravelapp]/config/ 配置文件丢失了。因此,我将另一个 Laravel 项目中丢失的文件复制回 config 目录,从而解决了问题。