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

时间:2014-10-20 19:06:52

标签: php session laravel laravel-4 laravel-routing

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

我在这里发现了一篇好文章http://dor.ky/laravel-prevent-sessions-for-routes-via-a-filter/,其目的就是为了这个目的。

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

我们能否以某种方式自定义sessios,以便仅为特定路由生成会话(或禁用特定路由)?

我可以通过具体的用例解释一下,请告诉我。

8 个答案:

答案 0 :(得分:8)

使用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.php放在providers下:

'App\Providers\SessionServiceProvider',

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

答案 1 :(得分:4)

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

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

现在,当对未使用stateful中间件组会话的路由发出请求时,不会发送回来。

答案 2 :(得分:2)

实现这一目标的最简单方法是创建自己的AppStartSession中间件,使其成为Illuminate \ Session \ Middleware \ StartSession的子类,并替换kernel.php中使用的类。您需要在子类中覆盖的唯一方法是sessionConfigured(),您可以返回false以禁用会话,或者使用parent :: 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,
    ];
}

不要与框架作斗争,拥抱它!

答案 3 :(得分:2)

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

答案 4 :(得分:1)

似乎有办法使用会话拒绝回调来完成此任务。

相关来源......

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

我无法在网络上找到很多对此的引用,但是通过源读取更多信息似乎如果会话拒绝回调返回真值,会话将被强制使用数组驱动程序来处理请求而不是配置的任何东西。您的回调也会获取当前请求,因此您可以根据请求参数执行某些逻辑。

我只在本地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

答案 5 :(得分:1)

我一直试图完成类似的功能。

我们的API是无状态的,除了1路 - 版本1购物车。

我最终在app / config / session.php中设置'driver',就像这样......

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

没什么神奇的。最初我们使用的是过滤器,但这种情况发生的时间不够早。

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

将交换机放在配置中似乎是一个容易让其他开发人员查看驱动程序的地方,而将其置于服务提供商中是如此隐蔽,不知道安装了哪些服务提供商以及他们与之交互的内容,调试起来会困难得多。

反正。希望这有一些用处。

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

这导致它的用途有限。一旦我们不再需要支持v1 / cart,我们将丢弃此路由,然后重新启动静态配置。

答案 6 :(得分:0)

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文件中,以免使用会话。

希望有帮助。

答案 7 :(得分:0)

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()”方法即可调用“ $ this-> 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'
    ]);
});
相关问题