阻止Laravel中路由的会话(自定义按需会话处理)


Prevent Sessions For Routes in Laravel (Custom on-demand session handling)

我正在使用laravel和设置为REDIS的默认会话驱动程序为我的Android应用程序构建API。

我在这里找到一篇好文章http://dor.ky/laravel-prevent-sessions-for-routes-via-a-filter/这在某种程度上起到了作用。

然而,当我点击url时,它也会点击redi并生成空的密钥。现在我想避免在redis中创建空会话密钥。理想情况下,它不应该击中redis。我该怎么做?

我们是否可以自定义会话,以便仅为特定路线生成会话(或为特定路线禁用会话)?

我可以用具体的用例来解释更多,请告诉我。

在Laravel 5中使用中间件真的很容易,我需要任何带有API密钥的请求来不进行会话,我只是这样做了:

<?php
namespace App'Http'Middleware;
use Closure;
use Illuminate'Session'Middleware'StartSession as BaseStartSession;
class StartSession extends BaseStartSession
{
    /**
     * Handle an incoming request.
     *
     * @param  'Illuminate'Http'Request  $request
     * @param  'Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if('Request::has('api_key'))
        {
            'Config::set('session.driver', 'array');
        }
        return parent::handle($request, $next);
    }
}

此外,您还需要扩展SessionServiceProvider,如下所示:

<?php namespace App'Providers;
use Illuminate'Session'SessionServiceProvider as BaseSessionServiceProvider;
class SessionServiceProvider extends BaseSessionServiceProvider
{
    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        $this->registerSessionManager();
        $this->registerSessionDriver();
        $this->app->singleton('App'Http'Middleware'StartSession');
    }
}

并将其放在config/app.phpproviders:下

'App'Providers'SessionServiceProvider',

此外,您必须在内核文件App/Http/Kernel.php中对其进行更改,在$middlewareGroups部分中,将默认条目'Illuminate'Session'Middleware'StartSession::class,更改为新类'App'Http'Middleware'StartSession::class,

在Laravel 5中,不要使用StartSessionShareErrorsFromSessionVerifyCsrfToken中间件。

在我的应用程序中,我已经将这三个中间件从web组移到了一个新的stateful组,然后我在需要了解会话的路由上包括了这个stateful组(在所有情况下,除了web之外,至少在我的程序中)。其他路由属于CCD_ 14或CCD_。

现在,当向不使用stateful中间件组的路由发出请求时,会话cookie不会被发回。

实现这一点的最简单方法是制作自己的AppStartSession中间件,该中间件子类为Illuminate''Session''middleware''StartSession,并替换kernel.php中使用的类。在子类中唯一需要重写的方法是sessionConfigured(),您可以返回false以禁用会话或父级::sessionConfigured)以允许它。

<?php
namespace App'Http'Middleware;
use Closure;
use Illuminate'Session'Middleware'StartSession;
class AppStartSession extends StartSession
{
    protected function sessionConfigured(){
        if(!'Request::has('api_key')){
            return false;
        }else{
            return parent::sessionConfigured();
        }
    }
}

kernel.php(有关更改的位置,请参阅***注释)

<?php
namespace App'Http;
use Illuminate'Foundation'Http'Kernel as HttpKernel;
class Kernel extends HttpKernel
{
    /**
     * The application's global HTTP middleware stack.
     *
     * @var array
     */
    protected $middleware = [
        'Illuminate'Foundation'Http'Middleware'CheckForMaintenanceMode::class,
        'App'Http'Middleware'EncryptCookies::class,
        'Illuminate'Cookie'Middleware'AddQueuedCookiesToResponse::class,
       // *** Replace start session class
       // 'Illuminate'Session'Middleware'StartSession::class,
        'App'Http'Middleware'AppStartSession::class,
        // *** Also comment these ones that depend on there always being a session.
        //'Illuminate'View'Middleware'ShareErrorsFromSession::class,
        //'App'Http'Middleware'VerifyCsrfToken::class,
    ];
    /**
     * The application's route middleware.
     *
     * @var array
     */
    protected $routeMiddleware = [
        'auth' => 'App'Http'Middleware'Authenticate::class,
        'auth.basic' => 'Illuminate'Auth'Middleware'AuthenticateWithBasicAuth::class,
        'guest' => 'App'Http'Middleware'RedirectIfAuthenticated::class,
    ];
}

不要对抗框架,拥抱它!

自从Laravel 5.2引入中间件组时,您可以通过在"web"中间件组(包括负责会话处理的StartSession中间件)之外定义它们来禁用某些路由的会话。与最新的5.2.x版本一样,整个默认的routes.php文件都用"web"中间件组包装,您需要在app/Providers/RouteServiceProvider.php文件中进行一些修改,如这里所述。

似乎有一种方法可以使用会话拒绝回调来实现这一点。

相关来源。。。

https://github.com/laravel/framework/blob/4.2/src/Illuminate/Foundation/Application.php#L655

https://github.com/laravel/framework/blob/4.2/src/Illuminate/Foundation/Application.php#L660

https://github.com/laravel/framework/blob/4.2/src/Illuminate/Session/Middleware.php#L60

https://github.com/laravel/framework/blob/4.2/src/Illuminate/Session/Middleware.php#L97

我在网上找不到太多关于这一点的参考,但通过阅读更多的源代码,如果会话拒绝回调返回一个truthy值,会话将被迫为请求使用数组驱动程序,而不是任何配置。回调还会注入当前请求,因此可以根据请求参数执行一些逻辑操作。

我只在本地的Laravel 4.2安装上测试过这个,但它似乎可以工作。您只需要将一个函数绑定到session.reject.

首先,创建一个SessionRejectServiceProvider(或类似的东西)

<?php
use 'Illuminate'Support'ServiceProvider;
class SessionRejectServiceProvider extends ServiceProvider {
    public function register()
    {
        $me = $this;
        $this->app->bind('session.reject', function($app)use($me){
            return function($request)use($me){
                return call_user_func_array(array($me, 'reject'), array($request));
            };
        });
    }
    // Put the guts of whatever you want to do in here, in this case I've
    // disabled sessions for every request that is an Ajax request, you
    // could do something else like check the path against a list and
    // selectively return true if there's a match.
    protected function reject($request)
    {
        return $request->ajax();
    }
}

然后将其添加到您的app/config/app.php 中的提供商

<?php
return array(
   // ... other stuff
   'providers' => array(
       // ... existing stuff...
       'SessionRejectServiceProvider',
   ),
);

编辑/更多信息

最终结果是,在会话启动之前,对应用程序的每个请求都会调用reject()方法。如果reject()方法返回true,会话将被设置为数组驱动程序,基本上什么都不做。您可以在$request参数中找到很多有用的信息来确定这一点,下面是4.2中请求对象的API引用。

http://laravel.com/api/4.2/Illuminate/Http/Request.html

我一直在尝试实现类似的功能。

我们的API是无状态的,除了1个路由-版本1的cart。

我最终在app/config/session.php中设置了'driver',如下所示。。。

'driver' => 'v1/cart' === Request::getDecodedPath() ? 'native' : 'array',

没有魔法。起初我们想使用前置过滤器,但这还不够早。

这似乎是一种简单的做事方式,但我可能遗漏了一些东西。

对于其他开发人员来说,将开关放在配置中似乎是一个很容易看到驱动程序是什么的地方,而将其放在服务提供商中则非常麻烦,因为不知道安装了什么服务提供商以及它们与什么交互,所以调试会困难得多。

不管怎样。希望这个有用。

如下所述。。。如果配置是动态的,请不要缓存它。

这确实导致它的用途有限。一旦我们不再需要支持v1/cart,我们就会放弃这个路由,然后回到静态配置。

Laravel默认有两个名为webapi的路由组,api路由组默认没有会话。

因此,我们可以将任何路由角色写入routes/api.php,不会使用会话默认值。

如果不想使用api前缀url,我们可以修改app'Providers'RouteServiceProvider添加一个新的组,如下所示:

Route::middleware('api')
    ->namespace($this->namespace)
    ->group(base_path('routes/static.php'));

现在您可以将任何路由放入routes/static.php文件中,不使用会话。

希望有帮助。

Laravel 5x

在App''Providers''RouteServiceProvider文件中,只需将mapApiRoutes()方法复制到一个名为mapStaticRoutes()的新方法中,删除前缀('api')调用,然后添加"routes/static.php";(您需要创建此文件)。这将使用相同的无状态";api";中间件,并且没有为路由分配/api前缀。

protected function mapStaticRoutes()
{
    Route::middleware('api')
         ->namespace($this->namespace)
         ->group(base_path('routes/static.php'));
}

只需更新";map()"方法调用"$这->mapStaticRoutes()"以便它知道你的新文件。任何添加到那里的路由现在都应该是无状态的,而且不需要太多工作。。。。。

public function map()
{
    $this->mapApiRoutes();
    $this->mapWebRoutes();
    // Static Routes (stateless, no /api prefix)
    $this->mapStaticRoutes();
}

static.php

// Health Check / Status Route (No Auth)
Route::get('/status', function() {
    return response()->json([
        'app'       => 'My Awesome App',
        'status'    => 'OK'
    ]);
});