codeigniter 3 SESSION的實現(基於redis)

###CI 2 SESSION的詬病 相信無數人在使用CI2的Session類庫時,遇到各類的坑,各類抱怨,各類不解。在CI中國論壇能搜到大量關於Session類庫的提問,說明要想用好session類庫仍是得下一番功夫。 ####Session和cookie的區別 在某些語境中,cookie是session的一種實現方式,Ci 2的類庫設計彷佛就這麼認爲的。因而,產生了CI2中COOKIE即SESSION的說法。在安全性方面,CI 2固然也由考慮,COOKIE是通過加密過的,並且一旦修改,服務器便再也不識別。php

**CI 2的session工做原理 **redis

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頭。cookie

####安全問題session

CI使用cookie來傳遞數據原本就不夠安全,並且若是數據量巨大時也會有性能問題。可是CI仍是友好地加入如下幾個安全驗證機制:tcp

加密令牌memcached

$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存儲就分析完畢了

相關文章
相關標籤/搜索