我最近创建了一个新的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
答案 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特性的供应商代码。您可以不加修改地使用它们,以及上面的两种方法。
这是我的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
目录,从而解决了问题。