Yii框架登录流程分析

 更新时间:2014年12月03日 10:16:38   投稿:shichen2014   我要评论
这篇文章主要介绍了Yii框架登录流程,详细的分析了Yii框架的原理与登录的详细流程,有助于深入了解Yii框架的原理,需要的朋友可以参考下

本文详细分析了Yii框架的登录流程。分享给大家供大家参考。具体分析如下:

Yii对于新手来说上手有点难度,特别是关于session,cookie和用户验证。现在我们就Yii中登录流程,来讲讲Yii开发中如何设置session,cookie和用户验证方面的一些通用知识

1. 概述

Yii是一个全栈式的MVC框架,所谓全栈式指的是Yii框架本身实现了web开发中所要用到的所有功能,比如MVC,ORM(DAO/ActiveRecord), 全球化(I18N/L10N), 缓存(caching), 基于jQuery Ajax支持(jQuery-based AJAX support), 基于角色的用户验证(authentication and role-based access control), 程序骨架生成器(scaffolding), 输入验证(input validation), 窗体小部件(widgets), 事件(events), 主题(theming), web服务(Web services),日志(logging)等功能. 详见官方说明.

这里要说的只是Yii的登录流程. 用Yii开发一般是用一个叫做Yii shell的控制台工具生成一个程序的骨架,这个骨架为我们分配好了按MVC方式开发web程序的基本结构,并且是一个可以直接运行的程序. 如果你了解 Ruby on Rails的话,原理是一样的.

2.网站登录流程

生成的程序中有一个protected目录,下面的controllers目录有个叫SiteController.php的文件,这个文件是自动生成的,里面有一个叫actionLogin的文件.程序登录流程默认就是从来开始的. Yii把类似于 http://domain.com/index.php?r=site/login 这样的地址通过叫router的组件转到上面说的actionLogin方法里的. 这个路由的功能不是的这里说的重点.actionLogin方法的代码是这样的.

复制代码 代码如下:
public function 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));
}

首先初始化一个LoginForm类,然后判断是否是用户点了登录后的请求(查看请求中有没有POST数据),如果是的话则先验证输入($model->validate)然后尝试登录($model->logiin),如果都成功,就跳转到登录前的页面,否则显示登录页面.

3.框架登录流程

LoginForm类继承于CFormModel,间接继承于CModel,所以他提供了CModel提供了一些像验证和错误处理方面的功能.其中的login方法就是执行验证操作的.方法首先通过用户提供的用户名和密码生成一个用来表示用户实体的UserIdentity类,该类中的authenticate方法执行实际的验证动作,比如从金沙国际官网中判断用户名和密码是否匹配. LoginForm类的login方法通过查询authenticate是否有错误发生来判断登录是否成功.如果成功则执行Yii::app()->user->login方法来使用户真正的的登录到系统中. 前面讲到的这些流程是用户程序提供的,而Yii::app()->user->login也就是CWebUser的login方法是Yii框架提供的流程.我们来看看他做了些什么.下面是该方面的代码,位于(Yii)webauthCWebUser.php文件中.

复制代码 代码如下:
public function login($identity,$duration=0){
$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))));
}
}

参数$identity是上面登录时生成的UserIdentity类,里面包含了基本的用户信息,如上面的Id,Name,还有可能是其它自定义的数据getPersistentStates. 程序首先把$identity中的数据复制到CWebUser的实例中,这个过程包括了生成相应的session,其实主要目的是生成session.然后根据参数$duration(cookie保存的时间)和allowAutoLogin属性来判断是否生成可以用来下次自动登录的cookie.如果是则生成cookie(saveToCookie).

复制代码 代码如下:
protected function saveToCookie($duration){
$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);
}

首先是新建一个CHttpCookie,cookie的key通过getStateKeyPrefix方法取得,该方法默认返回md5('Yii.'.get_class($this).'.'.Yii::app()->getId());即类名和CApplication的Id,这个Id又是crc32函数生成的一个值.这个具体的值是多少无关紧要. 但是每次都是产生一样的值的. 接着设置expire,cookie的过期时间,再新建一个array,包含了基本数据,接着比较重要的是计算取得cookie的值,$app->getSecurityManager()->hashData(serialize($data)), getSecurityManager返回一个CSecurityManager的对象,并调用hashData方法.

复制代码 代码如下:
public function hashData($data){
$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调用computHMAC方法生成一个hash值. hash的算法有SHA1和MD5两种,默认是用SHA1的. hash的时候还要生成一个validationKey(验证码)的,然后把验证码和要hash的值进行一些故意安排的运算,最终生成一个40位的SHA1,hash值.  hashData方法最终返回的是computeHMAC生成的hash值和经序列化的原始数据生成的字符串.这个过程有也许会有疑问. 如为什么要有验证码?

我们先来看一下基于cookie的验证是怎么操作的.服务器生成一个cookie后发送的浏览器中,并根据过期时间保存在浏览器中一段时间.用户每次通过浏览器访问这个网站的时候都会随HTTP请求把cookie发送过去,这是http协议的一部分, 与语言和框架无关的. 服务器通过判断发过来的cookie来决定该用户是否可以把他当作已登录的用户.但是cookie是客户端浏览器甚至其它程序发过来的,也就是说发过来的cookie可能是假的中被篡改过的.所以服务器要通过某种验证机制来判断是否是之后自己发过去的cookie.这个验证机制就是在cookie中包含一个hash值和生成这串hash值的原始数据.服务器接到cookie后取出原始数据,然后按原来的方法生成一个hash值来和发过来的hash值比较,如果相同,则信任该cookie,否则肯定是非法请求.比如我的Yii网站生成了这样一个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是网站统一生成的一个md5值. cookie value的值为两个部分,就是hashData方法生成的一个字符串.前面部分是hash值,后面是原始值.也就是说前面的1cbb64bdea3e92c4ab5d5cb16a67637158563114是hash值,后面是原始值.这个hash值是用SHA1生成的40位的字符串. 服务器把后面的原始值通过算法hash出一个值和这个传过来的hash值比较就知道是合法不审非法请求了. 那验证码呢?

如果服务器只是简单的把后面的原始值直接用SHA1或MD5,hash的话,那发送请求的人可以随意修改这个原始值和hash值来通过服务器的验证.因为SHA1算法是公开的,每个人都可以使用. 所以服务端需要在hash的时候加一个客户端不知道的验证码来生成一个客户端无法通过原始值得到正确hash的hash值(有点绕:) ). 这就是需要验证码的原因.并且这个验证码必须是全站通用的,所以上面的getValidationKey方法是生成一个全站唯一的验证码并保存起来.默认情况下,验证码是一个随机数,并保存在(yii)runtimestate.bin文件中.这样对每个请求来说都是一样的.

登录流程的最后就是把生成的cookie发送到浏览器中. 下次请求的时候可以用来验证.

希望本文所述对大家基于Yii框架的PHP程序设计有所帮助。

相关文章

  • CI框架中cookie的操作方法分析

    CI框架中cookie的操作方法分析

    这篇文章主要介绍了CI框架中cookie的操作方法,实例分析了CI框架操作cookie的三种常见方法,以及自定义扩展核心控制器类的实例加以分析说明,非常具有实用价值的技巧,需要的朋友可以参考下
    2014-12-12
  • laravel 使用事件系统浏览量的实现

    laravel 使用事件系统浏览量的实现

    今天小编就为大家分享一篇laravel 使用事件系统浏览量的实现,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-10-10
  • 基于PHP如何把汉字转化为拼音

    基于PHP如何把汉字转化为拼音

    将汉字转化为拼音是程序员们经常用到的操作任务之一,大家还经常见到ios 将汉字转化为拼音、excel汉字转化成拼音、excel汉字转化为拼音等,本文通过一段代码实例给大家介绍基于PHP如何把汉字转化为拼音,感兴趣的朋友一起学习吧
    2015-12-12
  • 正确的PHP匹配UTF-8中文的正则表达式

    正确的PHP匹配UTF-8中文的正则表达式

    这篇文章主要介绍了正确的PHP匹配UTF-8中文的正则表达式,本文对比给出了两个不同的正则表达式,需要的朋友可以参考下
    2015-05-05
  • PHP 二维数组和三维数组的过滤

    PHP 二维数组和三维数组的过滤

    本文给大家介绍PHP 二维数组和三维数组的过滤,涉及到php三维数组变二维数组的相关知识,本文介绍的非常详细,具有参考借鉴价值,感兴趣的朋友一起学习吧
    2016-03-03
  • PHP数组去重比较快的实现方式

    PHP数组去重比较快的实现方式

    使用PHP的array_unique()函数允许你传递一个数组,然后移除重复的值,返回一个拥有唯一值的数组,通过本文给大家介绍PHP数组去重比较快的实现方式,需要的朋友参考下本文
    2016-01-01
  • Laravel 5框架学习之环境与配置

    Laravel 5框架学习之环境与配置

    本文给大家主要介绍的是Laravel5框架中的环境配置,给大家详细介绍了.env的配置文件,包含的金沙国际官网配置信息的详细解释,这里推荐给大家,有需要的小伙伴参考下。
    2015-04-04
  • PHP屏蔽关键字实现方法

    PHP屏蔽关键字实现方法

    本篇文章主要介绍了PHP屏蔽关键字实现方法,具有一定的参考价值,有需要的可以了解一下。
    2016-11-11
  • 使用PHP实现阻止用户上传成人照片或者裸照

    使用PHP实现阻止用户上传成人照片或者裸照

    这篇文章主要介绍了使用PHP实现阻止用户上传成人照片或者裸照,方法和思路都非常的不错,推荐给大家,需要的朋友可以参考下
    2014-12-12
  • 简单谈谈php延迟静态绑定

    简单谈谈php延迟静态绑定

    php5.3是php5的一个里程碑,加入了大量新特性。本文主要给大家介绍了php5.3的一个新功能--延迟静态绑定,希望能够对大家有所帮助。
    2016-01-01

最新评论