我最近创建了一个新的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文件,我只创建了视图并将路线添加到我的路线.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']);
我对拉拉维尔没有太多经验,所以请原谅我的无知。我知道还有另一个问题问同样的事情,但这两个答案似乎都不适合我。感谢您的阅读!
编辑:
这是我的注册.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
如果您需要会话状态、CSRF 保护等,则需要使用 Web 中间件。
Route::group(['middleware' => ['web']], function () {
// your routes here
});
routes
添加到web middleware
中由于任何原因不起作用,请尝试将其添加到$middleware
Kernel.php
protected $middleware = [
//...
'Illuminate'Session'Middleware'StartSession::class,
'Illuminate'View'Middleware'ShareErrorsFromSession::class,
];
就我而言(使用 Laravel 5.3(,仅添加以下 2 个中间件允许我访问 API 路由中的会话数据:
-
'App'Http'Middleware'EncryptCookies::class
-
'Illuminate'Session'Middleware'StartSession::class
完整声明(内核.php $middlewareGroups
(:
'api' => [
'App'Http'Middleware'EncryptCookies::class,
'Illuminate'Session'Middleware'StartSession::class,
'throttle:60,1',
'bindings',
],
如果 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.
异常。
问题可能是您尝试在控制器的__constructor()
函数中访问会话。
从Laravel5.3+开始,这不再可能,因为它无论如何都不打算工作,如升级指南中所述。
在以前版本的 Laravel 中,您可以访问会话变量或 控制器构造函数中经过身份验证的用户。这是 从未打算成为框架的显式功能。在拉拉维尔 5.3,无法访问控制器构造函数中的会话或经过身份验证的用户,因为中间件尚未运行。
有关更多背景信息,请阅读泰勒的回应。
解决方法
如果仍想使用它,可以动态创建一个中间件并在构造函数中运行它,如升级指南中所述:
作为替代方案,您可以直接定义基于闭包的中间件 在控制器的构造函数中。在使用此功能之前,请确保 您的应用程序正在运行 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); }); } }
Laravel[5.4]
我的解决方案是使用全局会话助手:会话((
它的功能比$request->session((有点难。
写作:
session(['key'=>'value']);
推送:
session()->push('key', $notification);
正在检索:
session('key');
我正在使用Laravel 7.x,出现了这个问题..以下修复了它:
转到kernel.php
并将这两个类添加到protected $middleware
'Illuminate'Session'Middleware'StartSession::class,
'Illuminate'View'Middleware'ShareErrorsFromSession::class,
就我而言,我在$middlewareGroups中添加了以下 4 行(在 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/会话时,CSRF需要得到照顾。
我在Laravel Sanctum上遇到了这个错误。我通过在 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 应用程序的设置:
内核.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,记住我 cookie,以及用于 CSRF 的不安全 cookie,因此您使用
web
guard 进行身份验证,所有其他受保护的 JSON 返回路由都应使用auth:sanctum
中间件。
配置/身份验证.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()
按预期工作,配置最少,AuthenticatesUsers
和RegistersUsers
特征的最大使用。
以下是我的几个登录单元测试:
测试用例.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 身份验证特征中的 registered
和 authenticated
方法,以便它们返回用户对象而不仅仅是 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
- vendor/laravel/ui/auth-backend/AuthenticatesUsers.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 + 身份验证单元测试都达到了我的标准,所以希望我在这里的答案可以帮助将来节省其他人的时间。
我遇到了同样的错误,但这是由于我的 sanctum.php 文件中配置错误造成的。在有状态域的块中,我仍然有一个开发域而不是我的生产域。
'stateful' => explode(',', env(
'SANCTUM_STATEFUL_DOMAINS',
'mydomain.com')
),
它抛出了完全相同的错误。
希望对某人有所帮助。
干杯
在使用sanctum运行SPA身份验证测试时,您是否遇到此问题?
溶液:
将此行添加到tests/TestCase.php
:
public function setUp(): void
{
parent::setUp();
$this->withHeader('origin', config('app.url'));
}
解释:
为了将Sanctum用于SPA身份验证,您必须将其添加到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
为 null。
您可以在->redirect()
之前使用->stateless()
吗?然后,您不再需要该会话。
好的,这就是您面临的问题:您正在调用一个请求关联会话,该会话未实例化为您发出的请求。您只需要在请求上设置LaravelSession,该请求将在您希望在其上提供会话数据的请求上初始化会话。
$request->setLaravelSession(session())
在我的情况下,它只是为了把返回;在我设置会话的函数末尾<</p>
如果您使用的是 CSRF,请输入'before'=>'csrf'
在您的情况下 Route::get('auth/login', ['before'=>'csrf','uses' => 'Auth'AuthController@getLogin', 'as' => 'login']);
有关更多详细信息,请查看 Laravel 5 文档安全保护路线
它不在 laravel 文档中,我已经花了一个小时来实现这一点:
直到我使用"保存"方法,我的会话才持续存在......
$request->session()->put('lang','en_EN');
$request->session()->save();
Laravel 5.3+ Web 中间件组由 RouteServiceProvider 自动应用于您的 routes/web.php 文件。
除非您以不受支持的顺序修改内核$middlewareGroups数组,否则您可能正在尝试将请求作为构造函数的常规依赖项注入。
使用请求为
public function show(Request $request){
}
而不是
public function __construct(Request $request){
}
在我自己的情况下(在 Laravel 5.8 中(,位于 ../[mylaravelapp]/config/
目录中的 Laravel 项目中的session.php
配置文件丢失了。因此,我将丢失的文件从另一个Laravel项目复制回config
目录,从而解决了问题。
只需添加顶级公共/索引.php
ob_start();
它与共享主机一起工作
<小时 />如果不起作用,请尝试在app/Http/Middleware/TrustProxies中更改此代码.php
protected $proxies;
自
protected $proxies = '*';
以下内容对我有用...
在用户登录时创建会话
$r->session()->put('usrSession',$r->uName);
这里的"usrSession"是我的密钥,"uName"来自请求的变量(实际上是该用户的唯一用户名(
用户注销时的刷新(所有(会话
$r->session()->flush();
一些笔记可以帮助你,因为帮助了我:
正如这篇文章所说,dd('')
功能与session
功能有一些冲突(当然可能与 cookie 等其他一些功能,......我没有测试(;
对我来说,Reson是未知的! 也许dd()
清除缓冲区。
所以不要将dd()
与session
结合使用。
您应该将spa的域地址添加到"有状态"部分中的config/sanctum.php文件中