Yii框架登錄流程分析
本文詳細(xì)分析了Yii框架的登錄流程。分享給大家供大家參考。具體分析如下:
Yii對(duì)于新手來(lái)說(shuō)上手有點(diǎn)難度,特別是關(guān)于session,cookie和用戶(hù)驗(yàn)證?,F(xiàn)在我們就Yii中登錄流程,來(lái)講講Yii開(kāi)發(fā)中如何設(shè)置session,cookie和用戶(hù)驗(yàn)證方面的一些通用知識(shí)
1. 概述
Yii是一個(gè)全棧式的MVC框架,所謂全棧式指的是Yii框架本身實(shí)現(xiàn)了web開(kāi)發(fā)中所要用到的所有功能,比如MVC,ORM(DAO/ActiveRecord), 全球化(I18N/L10N), 緩存(caching), 基于jQuery Ajax支持(jQuery-based AJAX support), 基于角色的用戶(hù)驗(yàn)證(authentication and role-based access control), 程序骨架生成器(scaffolding), 輸入驗(yàn)證(input validation), 窗體小部件(widgets), 事件(events), 主題(theming), web服務(wù)(Web services),日志(logging)等功能. 詳見(jiàn)官方說(shuō)明.
這里要說(shuō)的只是Yii的登錄流程. 用Yii開(kāi)發(fā)一般是用一個(gè)叫做Yii shell的控制臺(tái)工具生成一個(gè)程序的骨架,這個(gè)骨架為我們分配好了按MVC方式開(kāi)發(fā)web程序的基本結(jié)構(gòu),并且是一個(gè)可以直接運(yùn)行的程序. 如果你了解 Ruby on Rails的話(huà),原理是一樣的.
2.網(wǎng)站登錄流程
生成的程序中有一個(gè)protected目錄,下面的controllers目錄有個(gè)叫SiteController.php的文件,這個(gè)文件是自動(dòng)生成的,里面有一個(gè)叫actionLogin的文件.程序登錄流程默認(rèn)就是從來(lái)開(kāi)始的. Yii把類(lèi)似于 http://domain.com/index.php?r=site/login 這樣的地址通過(guò)叫router的組件轉(zhuǎn)到上面說(shuō)的actionLogin方法里的. 這個(gè)路由的功能不是的這里說(shuō)的重點(diǎn).actionLogin方法的代碼是這樣的.
$model=new LoginForm;
// collect user input data
if(isset($_POST['LoginForm'])){
$model->attributes=$_POST['LoginForm'];
// validate user input and redirect to the previous page if valid
if($model->validate() && $model->login())
$this->redirect(Yii::app()->user->returnUrl);
}
// display the login form
$this->render('login',array('model'=>$model));
}
首先初始化一個(gè)LoginForm類(lèi),然后判斷是否是用戶(hù)點(diǎn)了登錄后的請(qǐng)求(查看請(qǐng)求中有沒(méi)有POST數(shù)據(jù)),如果是的話(huà)則先驗(yàn)證輸入($model->validate)然后嘗試登錄($model->logiin),如果都成功,就跳轉(zhuǎn)到登錄前的頁(yè)面,否則顯示登錄頁(yè)面.
3.框架登錄流程
LoginForm類(lèi)繼承于CFormModel,間接繼承于CModel,所以他提供了CModel提供了一些像驗(yàn)證和錯(cuò)誤處理方面的功能.其中的login方法就是執(zhí)行驗(yàn)證操作的.方法首先通過(guò)用戶(hù)提供的用戶(hù)名和密碼生成一個(gè)用來(lái)表示用戶(hù)實(shí)體的UserIdentity類(lèi),該類(lèi)中的authenticate方法執(zhí)行實(shí)際的驗(yàn)證動(dòng)作,比如從數(shù)據(jù)庫(kù)中判斷用戶(hù)名和密碼是否匹配. LoginForm類(lèi)的login方法通過(guò)查詢(xún)authenticate是否有錯(cuò)誤發(fā)生來(lái)判斷登錄是否成功.如果成功則執(zhí)行Yii::app()->user->login方法來(lái)使用戶(hù)真正的的登錄到系統(tǒng)中. 前面講到的這些流程是用戶(hù)程序提供的,而Yii::app()->user->login也就是CWebUser的login方法是Yii框架提供的流程.我們來(lái)看看他做了些什么.下面是該方面的代碼,位于(Yii)webauthCWebUser.php文件中.
$this->changeIdentity($identity->getId(),$identity->getName(),$identity->getPersistentStates());
if($duration>0){
if($this->allowAutoLogin)
$this->saveToCookie($duration);
else
throw new CException(Yii::t('yii','{class}.allowAutoLogin must be set true in order to use cookie-based authentication.',
array('{class}'=>get_class($this))));
}
}
參數(shù)$identity是上面登錄時(shí)生成的UserIdentity類(lèi),里面包含了基本的用戶(hù)信息,如上面的Id,Name,還有可能是其它自定義的數(shù)據(jù)getPersistentStates. 程序首先把$identity中的數(shù)據(jù)復(fù)制到CWebUser的實(shí)例中,這個(gè)過(guò)程包括了生成相應(yīng)的session,其實(shí)主要目的是生成session.然后根據(jù)參數(shù)$duration(cookie保存的時(shí)間)和allowAutoLogin屬性來(lái)判斷是否生成可以用來(lái)下次自動(dòng)登錄的cookie.如果是則生成cookie(saveToCookie).
$app=Yii::app();
$cookie=$this->createIdentityCookie($this->getStateKeyPrefix());
$cookie->expire=time()+$duration;
$data=array(
$this->getId(),
$this->getName(),
$duration,
$this->saveIdentityStates(),
);
$cookie->value=$app->getSecurityManager()->hashData(serialize($data));
$app->getRequest()->getCookies()->add($cookie->name,$cookie);
}
首先是新建一個(gè)CHttpCookie,cookie的key通過(guò)getStateKeyPrefix方法取得,該方法默認(rèn)返回md5('Yii.'.get_class($this).'.'.Yii::app()->getId());即類(lèi)名和CApplication的Id,這個(gè)Id又是crc32函數(shù)生成的一個(gè)值.這個(gè)具體的值是多少無(wú)關(guān)緊要. 但是每次都是產(chǎn)生一樣的值的. 接著設(shè)置expire,cookie的過(guò)期時(shí)間,再新建一個(gè)array,包含了基本數(shù)據(jù),接著比較重要的是計(jì)算取得cookie的值,$app->getSecurityManager()->hashData(serialize($data)), getSecurityManager返回一個(gè)CSecurityManager的對(duì)象,并調(diào)用hashData方法.
$hmac=$this->computeHMAC($data);
return $hmac.$data;
}
protected function computeHMAC($data){
if($this->_validation==='SHA1'){
$pack='H40';
$func='sha1';
}
else{
$pack='H32';
$func='md5';
}
$key=$this->getValidationKey();
$key=str_pad($func($key), 64, chr(0));
return $func((str_repeat(chr(0x5C), 64) ^ substr($key, 0, 64)) . pack($pack, $func((str_repeat(chr(0x36), 64) ^ substr($key, 0, 64)) . $data)));
}
hashData調(diào)用computHMAC方法生成一個(gè)hash值. hash的算法有SHA1和MD5兩種,默認(rèn)是用SHA1的. hash的時(shí)候還要生成一個(gè)validationKey(驗(yàn)證碼)的,然后把驗(yàn)證碼和要hash的值進(jìn)行一些故意安排的運(yùn)算,最終生成一個(gè)40位的SHA1,hash值. hashData方法最終返回的是computeHMAC生成的hash值和經(jīng)序列化的原始數(shù)據(jù)生成的字符串.這個(gè)過(guò)程有也許會(huì)有疑問(wèn). 如為什么要有驗(yàn)證碼?
我們先來(lái)看一下基于cookie的驗(yàn)證是怎么操作的.服務(wù)器生成一個(gè)cookie后發(fā)送的瀏覽器中,并根據(jù)過(guò)期時(shí)間保存在瀏覽器中一段時(shí)間.用戶(hù)每次通過(guò)瀏覽器訪(fǎng)問(wèn)這個(gè)網(wǎng)站的時(shí)候都會(huì)隨HTTP請(qǐng)求把cookie發(fā)送過(guò)去,這是http協(xié)議的一部分, 與語(yǔ)言和框架無(wú)關(guān)的. 服務(wù)器通過(guò)判斷發(fā)過(guò)來(lái)的cookie來(lái)決定該用戶(hù)是否可以把他當(dāng)作已登錄的用戶(hù).但是cookie是客戶(hù)端瀏覽器甚至其它程序發(fā)過(guò)來(lái)的,也就是說(shuō)發(fā)過(guò)來(lái)的cookie可能是假的中被篡改過(guò)的.所以服務(wù)器要通過(guò)某種驗(yàn)證機(jī)制來(lái)判斷是否是之后自己發(fā)過(guò)去的cookie.這個(gè)驗(yàn)證機(jī)制就是在cookie中包含一個(gè)hash值和生成這串hash值的原始數(shù)據(jù).服務(wù)器接到cookie后取出原始數(shù)據(jù),然后按原來(lái)的方法生成一個(gè)hash值來(lái)和發(fā)過(guò)來(lái)的hash值比較,如果相同,則信任該cookie,否則肯定是非法請(qǐng)求.比如我的Yii網(wǎng)站生成了這樣一個(gè)cookie:
cookie name:b72e8610f8decd39683f245d41394b56
cookie value: 1cbb64bdea3e92c4ab5d5cb16a67637158563114a%3A4%3A%7Bi%3A0%3Bs%3A7%3A%22maxwell%22%3Bi%3A1%3Bs%3A7%3A%22maxwell%22%3Bi%3A2%3Bi%3A3600%3Bi%3A3%3Ba%3A2%3A%7Bs%3A8%3A%22realname%22%3Bs%3A6%3A%22helloc%22%3Bs%3A4%3A%22myId%22%3Bi%3A123%3B%7D%7D
cookie name是網(wǎng)站統(tǒng)一生成的一個(gè)md5值. cookie value的值為兩個(gè)部分,就是hashData方法生成的一個(gè)字符串.前面部分是hash值,后面是原始值.也就是說(shuō)前面的1cbb64bdea3e92c4ab5d5cb16a67637158563114是hash值,后面是原始值.這個(gè)hash值是用SHA1生成的40位的字符串. 服務(wù)器把后面的原始值通過(guò)算法hash出一個(gè)值和這個(gè)傳過(guò)來(lái)的hash值比較就知道是合法不審非法請(qǐng)求了. 那驗(yàn)證碼呢?
如果服務(wù)器只是簡(jiǎn)單的把后面的原始值直接用SHA1或MD5,hash的話(huà),那發(fā)送請(qǐng)求的人可以隨意修改這個(gè)原始值和hash值來(lái)通過(guò)服務(wù)器的驗(yàn)證.因?yàn)镾HA1算法是公開(kāi)的,每個(gè)人都可以使用. 所以服務(wù)端需要在hash的時(shí)候加一個(gè)客戶(hù)端不知道的驗(yàn)證碼來(lái)生成一個(gè)客戶(hù)端無(wú)法通過(guò)原始值得到正確hash的hash值(有點(diǎn)繞:) ). 這就是需要驗(yàn)證碼的原因.并且這個(gè)驗(yàn)證碼必須是全站通用的,所以上面的getValidationKey方法是生成一個(gè)全站唯一的驗(yàn)證碼并保存起來(lái).默認(rèn)情況下,驗(yàn)證碼是一個(gè)隨機(jī)數(shù),并保存在(yii)runtimestate.bin文件中.這樣對(duì)每個(gè)請(qǐng)求來(lái)說(shuō)都是一樣的.
登錄流程的最后就是把生成的cookie發(fā)送到瀏覽器中. 下次請(qǐng)求的時(shí)候可以用來(lái)驗(yàn)證.
希望本文所述對(duì)大家基于Yii框架的PHP程序設(shè)計(jì)有所幫助。
- Yii2下點(diǎn)擊驗(yàn)證碼的切換實(shí)例代碼
- Yii2簡(jiǎn)單實(shí)現(xiàn)給表單添加驗(yàn)證碼的方法
- Yii2增加驗(yàn)證碼步驟詳解
- yii2中添加驗(yàn)證碼的實(shí)現(xiàn)方法
- Yii使用Captcha驗(yàn)證碼的方法
- yii實(shí)現(xiàn)創(chuàng)建驗(yàn)證碼實(shí)例解析
- Yii2實(shí)現(xiàn)多域名跨域同步登錄退出
- Yii框架用戶(hù)登錄session丟失問(wèn)題解決方法
- Yii2框架實(shí)現(xiàn)注冊(cè)和登錄教程
- Yii2中OAuth擴(kuò)展及QQ互聯(lián)登錄實(shí)現(xiàn)方法
- Yii中實(shí)現(xiàn)處理前后臺(tái)登錄的新方法
- Yii框架實(shí)現(xiàn)的驗(yàn)證碼、登錄及退出功能示例
相關(guān)文章
PHP小程序后臺(tái)部署運(yùn)行 LNMP+WNMP的方法
這篇文章主要介紹了PHP小程序后臺(tái)部署運(yùn)行 LNMP+WNMP的方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04ThinkPHP3.2.3框架實(shí)現(xiàn)的空模塊、空控制器、空操作,跳轉(zhuǎn)到錯(cuò)誤404頁(yè)面圖文詳解
這篇文章主要介紹了ThinkPHP3.2.3框架實(shí)現(xiàn)的空模塊、空控制器、空操作,跳轉(zhuǎn)到錯(cuò)誤404頁(yè)面,結(jié)合圖文形式詳細(xì)分析了thinkPHP3.2.3框架空模塊、空控制器、空操作,跳轉(zhuǎn)到錯(cuò)誤404頁(yè)面具體操作步驟與相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2019-04-04php中使用cookie來(lái)保存用戶(hù)登錄信息的實(shí)現(xiàn)代碼
php中使用cookie來(lái)保存用戶(hù)登錄信息的實(shí)現(xiàn)代碼,使用php開(kāi)發(fā)的朋友可以參考下2012-03-03php通過(guò)GD庫(kù)實(shí)現(xiàn)驗(yàn)證碼功能
這篇文章主要介紹了php通過(guò)GD庫(kù)實(shí)現(xiàn)驗(yàn)證碼功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-07-07Laravel 5框架學(xué)習(xí)之日期,Mutator 和 Scope
這篇文章主要介紹了Laravel 5框架學(xué)習(xí)之日期,Mutator 和 Scope的相關(guān)資料,需要的朋友可以參考下2015-04-04