Laravel 文档阅读:HTTP 会话
简介
HTTP 协议是无状态(stateless)协议,而会话(Session)提供了一种在多个请求之间存储用户信息的办法。Laravel 开箱支持用几款不同的软件(Memcached、Redis 和数据库)提供管理会话的能力,而且基于这几款软件封装的 API 是一样的。
配置
会话的配置文件是 config/session.php
,这里面配置项你可以深情款款地看一遍。Laravel 默认使用的会话驱动是 file
,对于许多项目来说,够用了。对于大型项目,为了获得更好的会话性能,可以考虑使用 memchached
或者 redis
驱动。
会话数据保存在哪个地方,取决于 driver
配置项取值。Laravel 开箱支持以下驱动:
file
- 会话数据保存在storage/framework/sessions
目录下。cookie
- 会话数据经过加密保存在 Cookie 中。database
- 会话数据保存在关系型数据库中。memchached
/redis
- 会话数据存储在这两个基于缓存的存储设备中。array
- 会话数据临时保存在数组中,不会被持久化。
提示!
array
驱动在测试时使用的,它不会将会话里的数据持久化。
驱动预设
数据库
当使用 database
会话驱动的时候,你需要在数据库创建一张表格,存储这些会话数据。下面是使用 Schema
声明会话表的脚本:
Schema::create('sessions', function ($table) {
$table->string('id')->unique();
$table->unsignedInteger('user_id')->nullable();
$table->string('ip_address', 45)->nullable();
$table->text('user_agent')->nullable();
$table->text('payload');
$table->integer('last_activity');
});
你可以使用 Artisan 命令生成这个迁移文件:
php artisan session:table
php artisan migrate
Redis
在使用 Redis 之前,需要先用 Composer 安装 predis/predis
包(~1.0)。然后在 config/database.php
中配置你的 Redis 连接,最后为 config/session.php
的 connection
字段指定使用哪个 Redis 连接。
使用 Session
获得数据
有两种方式操作会话数据:全局 session
辅助函数或者通过 Request
实例。首先,先来看通过 Request
实例的方式,Request
实例在控制器方法里可以依赖注入。记住,控制器方法里的依赖是通过服务容器自动注入的。
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class UserController extends Controller
{
/**
* Show the profile for the given user.
*
* @param Request $request
* @param int $id
* @return Response
*/
public function show(Request $request, $id)
{
$value = $request->session()->get('key');
//
}
}
get
方法还接收第二个参数,它是默认值——当会话中没有要取的 Key 时,就返回这个值。第二个参数还可以是一个闭包,当会话中没有要取的 Key 时,就执行这个闭包里的内容,闭包的返回结果就是默认值:
$value = $request->session()->get('key', 'default');
$value = $request->session()->get('key', function () {
return 'default';
});
全局 session
辅助函数
你也可以使用全局 session
辅助函数获得、保存会话数据。当给 session()
函数传递一个字符串参数的时候,它会返回会话中指定 Key 的值。当传递给 session()
的是一个包含键值对的数组,数组里的值都会保存到会话里:
Route::get('home', function () {
// Retrieve a piece of data from the session...
$value = session('key');
// Specifying a default value...
$value = session('key', 'default');
// Store a piece of data in the session...
session(['key' => 'value']);
});
提示! 通过 HTTP 请求实例和全局
session
辅助函数操作会话数据的方法几乎没有区别。两种方法都可以在你的测试用例中获得,使用assertSessionHas
方法测试。
获得所有会话数据
使用 all
方法:
$data = $request->session()->all();
$data = session()->all();
判断会话里是否存在指定 Key
有两个方法用来判断:has
和 exists
。
-
has
方法:当指定的 Key 存在于会话中,且值不为null
时,返回false
,否则返回true
。if ($request->session()->has('users')) {
//
} -
exists
方法:当指定的 Key 存在于会话中,就返回true
,否则返回false
。if ($request->session()->exists('users')) {
//
}
保存数据
向会话里保存数据使用 put
方法,或者使用 session
辅助函数:
// Via a request instance...
$request->session()->put('key', 'value');
// Via the global helper...
session(['key' => 'value']);
向数组类型的会话数据里推入数据
如果会话里有一个字段值是一个数组的话,如果要往这个数组里推入数据,就需要用到 push
方法。例如,user.teams
这个 Key 保存的是队名,现在我们给这个数组里再加入一个元素:
$request->session()->push('user.teams', 'developers');
获得 & 删除 Key
pull
方法会在获得 Key 值的同时从会话里删除这个 Key 数据记录。
$value = $request->session()->pull('key', 'default');
闪存数据
有时,你可能希望保存的会话数据只在下一个请求中有效,这时可以用 flash
方法。用这个方法保存的数据只在下一个的请求中能够得到,之后就被删除。闪存数据主要用在保存短生命周期的消息比较有用:
$request->session()->flash('status', 'Task was successful!');
如果要让闪存数据多维持几个请求周期,可以使用 reflash
方法,这个方法会让所有的闪存数据延长一个请求周期。如果只延长特定的一些闪存数据,就用 keep
方法:
$request->session()->reflash();
$request->session()->keep(['username', 'email']);
删除数据
forget
方法用来删除会话数据,如果要删除所有会话数据,请使用 flush
方法:
$request->session()->forget('key');
$request->session()->flush();
重新生成会话 ID
重新生成会话 ID 的原因,通常是为了避免恶意用户利用 会话固定 手段攻击你的项目。
如果你使用了内置的 LoginController
的话,它会在你认证的时候自动重新生成会话 ID;如果,你需要手动重新生成会话 ID 的话,请使用 regenerate
方法。
$request->session()->regenerate();
添加自定义会话驱动
实现驱动
你的自定义驱动要实现 SessionHandlerInterface
这个接口。这个接口包含几个需要实现的简单方法。一个 MongoDB
的实现代码看起来是想这样的:
<?php
namespace App\Extensions;
class MongoHandler implements SessionHandlerInterface
{
public function open($savePath, $sessionName) {}
public function close() {}
public function read($sessionId) {}
public function write($sessionId, $data) {}
public function destroy($sessionId) {}
public function gc($lifetime) {}
}
注意! Laravel 没有为你的驱动扩展创建默认文件目录。你可以按照你的心意放置,在这里我们是创建了一个
Extensions
目录保存我们的MongoHandler
文件。
由于所有的方法看起来都不知道是什么意思,我这里全部讲一遍:
open
方法用在基于文件的会话存储系统。因为 Laravel 自带file
会话存储,所以这个方法保持为空就可以了。这个方法有些不使用,不是一个很好的接口设计(之后再讨论),但是 PHP 要求我们去实现它。close
方法跟open
方法一样,可以直接忽略,保持为空即可。对于大多数驱动,都用不着。read
方法应该返回匹配指定$sessionId
的那个会话数据的字符串形式,在你的驱动程序中查询或存储会话数据时,无需进行任何序列化或其他编码,因为 Laravel 给你做了。write
方法应该将给定的$data
字符串数据关联到$sessionId
,然后持久化、保存到存储系统里。比如 MongoDB、Dynamo 等。再一次说明,你不应该执行任何序列化操作——Laravel 会为你处理好。destroy
方法应该从持久化系统里删除与$sessionId
关联的会话数据。gc
方法应该删除在$lifetime
之前的所有会话数据,它是一个时间戳。对于自带过期功能的系统,像 Memcached 和 Redis,这个方法保持为空就 OK 了。
注册驱动
驱动实现好后,就可以注册它了。为 Laravel 注册驱动要用到 Session
门面的 extend
方法。你需要在服务提供者的 boot
方法里调用 extend
方法。可以在现成的 AppServiceProvider
中,或者其他新建的服务提供者里:
<?php
namespace App\Providers;
use App\Extensions\MongoSessionStore;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\ServiceProvider;
class SessionServiceProvider extends ServiceProvider
{
/**
* Perform post-registration booting of services.
*
* @return void
*/
public function boot()
{
Session::extend('mongo', function ($app) {
// Return implementation of SessionHandlerInterface...
return new MongoSessionStore;
});
}
/**
* Register bindings in the container.
*
* @return void
*/
public function register()
{
//
}
}
会话驱动注册好后,就可以在 config/session.php
配置文件里使用 mongo
驱动了。
本作品采用《CC 协议》,转载必须注明作者和本文链接
我的 session 配置打开了关闭浏览器 session失效就是不生效
'lifetime' => env('SESSION_LIFETIME', 60),