我正在使用laravel和默认会话驱动程序设置为REDIS为我的Android应用程序构建API。
我在这里找到了一篇很好的文章http://dor.ky/laravel-prevent-sessions-for-routes-via-a-filter/,这是为了达到目的。
然而,当我点击URL时,它也会击中redis并生成空的键。现在我想避免在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.php
下的providers
:
'App\Providers\SessionServiceProvider',
您还必须在内核文件中更改它:App/Http/Kernel.php
,在$middlewareGroups
部分中将默认条目\Illuminate\Session\Middleware\StartSession::class,
更改为新类\App\Http\Middleware\StartSession::class,
。
在Laravel 5中,不要使用StartSession
,ShareErrorsFromSession
和VerifyCsrfToken
中间件。
在我的应用程序中,我将这三个中间件从web
组移动到一个新的stateful
组,然后我将这个stateful
组包含在需要了解会话的路线上(除了所有情况下的web
,在我的应用程序中)最小)。其他路线属于web
或api
组。
现在,当向不使用stateful
中间件组会话的路由发出请求时,不会发送回cookie。
实现这一目标的最简单方法是创建自己的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,
];
}
不要打架子,拥抱它!
从Laravel 5.2开始,当引入中间件组时,您可以通过在“Web”中间件组(包括负责会话处理的StartSession中间件)之外定义它们来禁用某些路由的会话。与最新的5.2.x版本一样,整个默认routes.php文件都包含“web”中间件组,您需要在app/Providers/RouteServiceProvider.php
文件中进行一些修改,如here所述。
似乎有一种方法可以使用会话拒绝回调来实现此目的。
相关来源......
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参考。
我一直在努力完成类似的功能。
我们的API是无状态的,除了1路 - 版本1购物车。
我最终在app / config / session.php中设置了'driver'
,就像这样......
'driver' => 'v1/cart' === Request::getDecodedPath() ? 'native' : 'array',
没什么了不起的。最初我们虽然使用了之前的过滤器,但这种情况并没有及早发生。
这似乎是一种简单的做事方式,但我可能会遗漏一些东西。
将交换机放在配置中似乎是一个容易让其他开发人员看到驱动程序的地方,而将它放在服务提供商中是如此隐蔽,不知道安装了什么服务提供商以及他们与之交互的内容,它将是更难调试。
无论如何。希望这有一些用处。
正如下面所指出的......如果动态,请不要缓存您的配置。
这导致它的用途有限。一旦我们不再需要支持v1 / cart,我们将丢弃此路由,然后返回静态配置。
Laravel默认有两个路由组叫做web
和api
,api路由组默认没有session。
因此,我们可以将任何路由角色写入routes/api.php
,不会使用会话默认值。
如果不想使用api前缀url,我们可以修改app\Providers\RouteServiceProvider
添加一个像这样的新组:
Route::middleware('api')
->namespace($this->namespace)
->group(base_path('routes/static.php'));
现在你可以将任何路由放入routes/static.php
文件中,不会使用session。
希望有帮助。