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 文件,我只是创建了视图,并将路由添加到我的 outoutes.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 没什么经验,所以请原谅我的无知。我知道 另一个问题也在问同样的问题,但是这两个答案似乎都不适合我。感谢您的阅读!

编辑:

这是我要的 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
209111 次浏览

如果需要会话状态、 CSRF 保护等,则需要使用 网络中间件

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

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

请注意,VerifyCsrfTokenStartSession之后。如果您以不同的顺序得到它们,它们之间的依赖关系也会导致 Session store not set on request.异常。

如果在 web middleware中加入你的 routes因为任何原因都不起作用,那么试着将它加入到 $middlewareKernel.php

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

在我的例子中(使用 Laravel 5.3) ,只添加了以下两个中间件,允许我访问 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',
],

Laravel [5.4]

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

它的功能比 < em > $request-> session () 稍微难一点。

写作 :

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

推进 :

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

检索 :

session('key');

对我来说,这只是为了 报税表; 在功能结束时,我已经设置会话

一个问题可能是你试图 访问控制器的 __constructor()函数中的会话。

从 Laravel 5.3 + 这是不可能的了,因为它不打算工作反正,如升级指南所述

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

对于更多的背景信息也阅读 泰勒他的回应。

解决办法

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

作为替代方案,您可以直接定义基于 Closure 的中间件 在您的控制器的构造函数中。在使用此特性之前,请确保 您的应用程序正在运行 Laravel5.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);
});
}
}

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

对你来说 Route::get('auth/login', ['before'=>'csrf','uses' => 'Auth\AuthController@getLogin', 'as' => 'login']);

有关详细信息,请查看 Laravel5文档 安全保护路由

你能在 ->redirect()之前使用 ->stateless()吗。 那你就不需要治疗了。

在我的示例中,我将以下4行添加到 $midwareGroups (在 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',
],

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

否则将出现“ CSRF 令牌不匹配”错误。我在这里挣扎了好几个小时就是为了找到顺序的重要性。

这允许我访问 API 中的会话。我还添加了 VerifyCsrfToken,因为当涉及 cookie/session 时,需要处理 CSRF。

幼虫记录上没有,我花了一个小时才搞清楚:

我的疗程并没有持续,直到我使用“保存”方法..。

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

Laravel 5.3 + web 中间件组由 RouteServiceProvider 自动应用到路由/web.php 文件中。

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

使用请求作为

public function show(Request $request){


}

而不是

public function __construct(Request $request){


}

我在 Laravel 至圣所出现了这个错误。我通过在 Kernel.php 中的 api中间件组中添加 \Illuminate\Session\Middleware\StartSession::class,来解决这个问题,但是我后来发现这个方法“有效”,因为我的身份验证路由是在 api.php中添加的,而不是在 web.php中,所以 Laravel 使用了错误的身份验证保护。

我把这些路线移动到 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');

在我得到另一个关于 RequestGuard::logout()的奇怪错误之后,我发现这个问题并不存在。

它让我意识到我的自定义认证路由是从 AuthenticatesUsers 特性调用方法,但是我没有使用 Auth::routes()来实现它。然后我意识到 Laravel 默认使用网络警卫,这意味着路由应该在 routes/web.php中。

这是我现在使用 Sanctum 和一个去耦 Vue SPA 应用程序的设置:

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

注意: 对于 Laravel Sanctum 和同域 Vue SPA,您使用 httpOnly cookie 作为会话 cookie,请记住 me cookie 和不安全 cookie 作为 CSRF,因此您使用 web约束作为 auth,其他受保护的、返回 JSON 的路由应该使用 auth:sanctum中间件。

Config/auth.php

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


...


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


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

然后您可以进行这样的单元测试,其中关键的是,Auth::check()Auth::user()Auth::logout()可以按照预期的方式工作,只需要最小限度地配置和最大限度地使用 AuthenticatesUsersRegistersUsers特性。

下面是我的几个登录单元测试:

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

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

我重写了 Laravel auth trait 中的 registeredauthenticated方法,这样它们返回的是用户对象,而不仅仅是204个选项:

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


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

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

  • Vendor/laravel/ui/auth-backend/RegistersUsers.php
  • 日志文件//////////////////////////////////////////////////////

以下是我的 Vue SPA 的登录 Vuex 操作:

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

我花了一个多星期的时间才使 Laravel Sanctum + 同域 Vue SPA + auth 单元测试全部达到我的标准,所以希望我在这里的回答可以帮助其他人在未来节省时间。

我正在使用 Laravel 7.x,这个问题出现了. . 下面解决了它:

转到 kernel.php并将这两个类添加到 protected $middleware

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

在我自己的例子中(在 Laravel 5.8中) ,我的 Laravel 项目中位于 ../[mylaravelapp]/config/目录中的 session.php配置文件丢失了。因此,我将另一个 Laravel 项目中丢失的文件复制回 config目录,这修复了问题。

好的,这里是您所面临的: 您正在调用一个请求关联会话,该会话没有实例化到您所发出的请求。您只需要在请求上设置 LaravelSession,该请求将在您希望会话数据可用的请求上初始化会话。

$request->setLaravelSession(session())

我有同样的错误,但这是由于在我的 santum.php 文件错误配置。在有状态域的块内部,我仍然有一个开发域,而不是我的生产域。

'stateful' => explode(',', env(
'SANCTUM_STATEFUL_DOMAINS',
'mydomain.com')
),

它抛出了完全相同的错误。

希望这对某人有帮助。
干杯

您在运行带密室的 SPA 身份验证测试时遇到这个问题了吗?

解决方案:

将这一行添加到 tests/TestCase.php:


public function setUp(): void
{
parent::setUp();
$this->withHeader('origin', config('app.url'));
}

说明:

为了对 SPA auth 使用肤色,您必须将其添加到 api 中间件:

\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class

EnsureFrontendRequestsAreStateful类只有在其静态方法 fromFrontend返回 true 时才能工作:

 public static function fromFrontend($request)
{
$domain = $request->headers->get('referer') ?: $request->headers->get('origin');


if (is_null($domain)) {
return false;
}
// ... ommited
}

未设置会话存储,因为在单元测试中运行此方法时,$domain为空。

只要加上最上面的 Public/index.php

ob_start();

是和共享主机一起工作


如果不工作尝试改变这个代码在 App/Http/Middleware/TrustProxies.php

protected $proxies;

protected $proxies = '*';

下面这些对我很有用。

在用户登录时进行会话

$r->session()->put('usrSession',$r->uName);

这里‘ usrSession’是我的键,‘ uName’来自 request 的变量(实际上它是该用户的唯一用户名)

当用户注销时刷新(所有)会话

$r->session()->flush();