codeigniter 3 SESSION的实现(基于redis)

###CI 2 SESSION的诟病 相信无数人在使用CI2的Session类库时,遇到各种的坑,各种抱怨,各种不解。在CI中国论坛能搜到大量关于Session类库的提问,说明要想用好session类库还是得下一番功夫。 ####Session和cookie的区别 在某些语境中,cookie是session的一种实现方式,Ci 2的类库设计似乎就这么认为的。于是,产生了CI2中COOKIE即SESSION的说法。在安全性方面,CI 2当然也由考虑,COOKIE是经过加密过的,而且一旦修改,服务器便不再识别。

**CI 2的session工作原理 **

CI 2提供了一个元数据,我们可以把这个元数据看为一个自定义的验证机制,其包含以下内容:

Array
(
    [session_id] => 4a5a5dca22728fb0a84364eeb405b601
    [ip_address] => 127.0.0.1
    [user_agent] => Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7;
    [last_activity] => 1303142623
)

其中Session id是重要的,Session id不对,直接拒绝。 验证选项在配置文件里有规定,(IP地址的限制)(user agent限制)(上次活动时间)等

$config['sess_match_ip']  = FALSE;
$config['sess_match_useragent'] = TRUE;
$config['sess_time_to_update'] = 300;

特别是当设置sess_match_useragent设为TRUE时,会遇到各种的坑: 你用flash组件上传文件,只有登录的用户才能上传文件,结果你每次判断用户是否登录都会出错,因为flash发送的http请求有可能更改了user agent; 使用ie切换不同的模式,比如兼容模式,也会造成user agent不同; user agent的长度最长是120个字符,手动设置User agent是需要截取字符到最大120个。 另外,如果出现“Cannot modify header information - headers already sent by”错误,基本可以断定是你文件的编码格式有误,请去掉bom头。

####安全问题

CI使用cookie来传递数据本来就不够安全,而且如果数据量巨大时也会有性能问题。但是CI还是友好地加入以下几个安全验证机制:

加密令牌

$config['encryption_key'] = 'mahuaz_';
$config['sess_encrypt_cookie'] =  TRUE;

设置后,客户端检查cookie时就可以看到加密后的序列化数据。

自动更新机制

CI默认每五分钟更新一次令牌,更新发生在客户端的一次请求中。客户端每发送一次请求,会把cookie的信息发送到服务器,服务器根据发来的cookie判断是否到了应该更换令牌的时间了,如果是,就会重新换一个新的令牌返回给客户端。这就相当于门卫给你换了令牌,下次要使用新令牌进门。此时即使有坏人伪造了一个令牌也不起作用了,因为旧令牌已经作废。这样就相当于加了一条安全机制。可以使用:

$config['sess_time_to_update'] = 300;

来设置多长时间来换一次令牌。这个时间不要设置的太短,更新频繁也会影响性能。这里不要和sess_expiration混淆:

$config['sess_expiration']  = 7200;

这个配置是用来指示整个cookie的过期时间的,相当于令牌完全失效,再怎么更换都不起作用。

###CI 3的变更 CI3的Session的重大改变就是默认使用了原生的Session,这符合Session类库本来的意思,似乎更加合理一些。总体来说,虽然设计理念不同,但为了保证向后兼容性,类库的使用方法与CI2.0的差别不是很大。一般的使用过程是这样的:

截取一段CI2 SESSION的代码:

         if ($this->sess_encrypt_cookie == TRUE)
                {
                        $this->CI->load->library('encrypt');
                }

                if ($this->sess_use_database === TRUE AND $this->sess_table_name != '')
                {
                        $this->CI->load->database();
                }


                $this->now = $this->_get_time();

  
                if ($this->sess_expiration == 0)
                {
                        $this->sess_expiration = (60*60*24*365*2);
                }


                $this->sess_cookie_name = $this->cookie_prefix.$this->sess_cookie_name;


截取一段CI3 SESSION的代码:

	$class = $this->_ci_load_classes($this->_driver);

		// Configuration ...
		$this->_configure($params);

		$class = new $class($this->_config);
		if ($class instanceof SessionHandlerInterface)
		{
			if (is_php('5.4'))
			{
				session_set_save_handler($class, TRUE);
			}
			else
			{
				session_set_save_handler(
					array($class, 'open'),
					array($class, 'close'),
					array($class, 'read'),
					array($class, 'write'),
					array($class, 'destroy'),
					array($class, 'gc')
				);

				register_shutdown_function('session_write_close');
			}
		}
		else
		{
			log_message('error', "Session: Driver '".$this->_driver."' doesn't implement SessionHandlerInterface. Aborting.");
			return;
		}

可以看到CI 3已经完全重写了SESSION,由不同的驱动器用来保存SESSION(并且淘汰了COOKIE)。

###CI3 SESSION FOR REDIS 在配置文件中,CI 3的配置也完全缩减了很多

$config['sess_driver'] = 'files';
$config['sess_cookie_name'] = 'ci_session';
$config['sess_expiration'] = 7200;
$config['sess_save_path'] = NULL;
$config['sess_match_ip'] = FALSE;
$config['sess_time_to_update'] = 300;
$config['sess_regenerate_destroy'] = FALSE;

CI 3 可以配置驱动器类型,包括files, database, redis, memcached以及自定义,$config['sess_driver'] 来配置驱动器,默认的驱动器是files。官方推荐用files类型(在一般情况下) 配置session save path 配置节sess_save_path会根据不同的驱动器,定义不同。 为了适用redis,我这里将他配置为

tcp://127.0.0.1:6379

在上面的代码中,有下面这两句

$class = new $class($this->_config);
		if ($class instanceof SessionHandlerInterface){
...
}

确立了$_SEESION 由 redis进行存储,加载的类是Session_redis_driver(位于sytstem/libraries/Session_redis_driver),在测试控制器中, 我们写一些测试代码:

    $_SESSION['test'] = 'There is test!';
    var_dump($_SESSION);

会打印出

array(2) { ["__ci_last_regenerate"]=> int(1444637502) ["test"]=> string(13) "There is test" } 

我们在Session_redis_driver的read方法中写到

var_dump($this->_key_prefix.$session_id);  //redis  key的值,由_key_prefix.$session_id组合构成

会打印出

string(51) "ci_session:23ea4298dc5e7d6b808ca70ddb1665590e5cfb58"

为了测试redis,我们可以在PHP中测试:

$redis = new redis();
$redis->connect('127.0.0.1',6379);
var_dump($redis->get("ci_session:23ea4298dc5e7d6b808ca70ddb1665590e5cfb58"));

会打印出

string(60) "__ci_last_regenerate|i:1444637502;test|s:13:"There is test";"

同样,我们在redis-cli中输入

get ci_session:23ea4298dc5e7d6b808ca70ddb1665590e5cfb58

会打印出

__ci_last_regenerate|i:1444637502;test|s:13:"There is test

至此,CI 3 使用REDIS作为SESSION存储就分析完毕了

转载于:https://my.oschina.net/lwl1989/blog/515927

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值