【Yii】Authentication (1)

  大多数网站都有身份验证系统,用户必须登录才能发表文章、评论内容甚至管理网站等等。无论如何,在用户进行任何操作前对其身份的检验是必须的。Yii框架自动生成的网站中使用内嵌的验证程序,下面三个文件会自动生成,用来管理验证:

  LoginForm.php定义相应的规则和行为login.php即登录时的form本身,UserIdentity.php定义了执行实际验证功能的model。当然,protected/controllers/SiteController.php中的部分代码使得action可以执行,即controller。

 

  UserIdentity.php中是身份验证的核心内容,默认的代码如下:

public function authenticate()
    {
        $users=array(
            // username => password
            'demo'=>'demo',
            'admin'=>'admin',
        );
        if(!isset($users[$this->username]))
            $this->errorCode=self::ERROR_USERNAME_INVALID;
        else if($users[$this->username]!==$this->password)
            $this->errorCode=self::ERROR_PASSWORD_INVALID;
        else
            $this->errorCode=self::ERROR_NONE;
        return !$this->errorCode;
    }

  这里采用硬编码将用户名称和密码写进方法里,当然,绝大多数网站不可能这么做,身份验证基本上都要跟数据库联系起来。那么该如何通过数据库中的数据来验证呢?

 

  在这之前,我们先来看看Yii中实现身份验证的流程。

  当我们点击login时,浏览器将跳转到www.example.com/index.php/site/login,因为Yii将actionLogin()设为SiteController的默认执行方法。actionLogin()方法如下:

public function actionLogin()
{
    $form=new LoginForm;
    if(isset($_POST['LoginForm']))
    {
        $form->attributes=$_POST['LoginForm'];
        // validate user input and redirect to previous page if valid
        if($form->validate()  && $form->login()) $this->redirect(Yii::app()->user->returnUrl);
    }
    // display the login form
    $this->render('login',array('form'=>$form));
}

  首先,一个LoginForm的对象$form被创建,该类由Model类LoginForm定义。如果用户登陆的数据被提交,那么$form立刻收集数据并且进行验证。如果通过,页面将跳转到用户之前所在的页面。如果没有通过,那么login form和附带的错误信息将被显示。

 

  上面的validate()方法意味着数据必须通过Model类LoginForm中的rules()规则,即:

public function rules()
{
    return array(
        array('username, password', 'required'),
        array('password', 'authenticate'),
    );
}

  其中username、password都必须填写,并且password要通过authenticate()方法的验证,这个方法被定义在LoginForm中,即:

public function authenticate($attribute,$params)
    {
        if(!$this->hasErrors())
        {
            $this->_identity=new UserIdentity($this->username,$this->password);
            if(!$this->_identity->authenticate())
                $this->addError('password','Incorrect username or password.');
        }
    }

  当没有input errors时,一个UserIdentity的对象被创建,username、password被传入构造函数。Useridentity对象的authenticate()方法被调用。

  整个身份验证的过程大致如下图所示:

  

 

  接下来我们要实现通过数据库来进行身份验证。

  先从最底层改起,修改UserIdentity中的authenticate()方法如下:

public function authenticate()
    {
        $user = User::model()->findByAttributes(array('username'=>$this->username));
        if ($user===null) { 
             $this->errorCode=self::ERROR_USERNAME_INVALID;
        } else if ($user->password!== SHA1($this->password) ) { 
             $this->errorCode=self::ERROR_PASSWORD_INVALID;
        } else { // Okay!
             $this->errorCode=self::ERROR_NONE;
        }
        return !$this->errorCode;
    } 

  其中通过Model类User查询username匹配的条目,返回一个User对象,如果返回对象为空,那验证失败,将errorCode赋值。如果密码不匹配,同样验证也失败(此处使用SHA1加密算法)。如果一切正常,那么errorCode赋值ERROR_NONE。

  接着修改Model类LoginForm中的authenticate():

public function authenticate($attribute,$params)
{
    if(!$this->hasErrors())  // we only want to authenticate when no input errors
    {
        $identity=new UserIdentity($this->username,$this->password);
        $identity->authenticate();
        switch($identity->errorCode)
        {
            case UserIdentity::ERROR_NONE:
                $duration=$this->rememberMe ? 3600*24*30 : 0; // 30 days
                Yii::app()->user->login($identity,$duration);
                break;
            case UserIdentity::ERROR_USERNAME_INVALID:
                $this->addError('username','Username is incorrect.');
                break;
            default: // UserIdentity::ERROR_PASSWORD_INVALID
                $this->addError('password','Password is incorrect.');
                break;
        }
    }
}

  这里调用UserIdentity中的authenticate()方法,通过产生的errorCode来判断该执行何种操作。

  至此,便完成了使用数据库中的用户信息进行身份验证的功能。更复杂的身份验证将在【Yii】Authentication (2) 中讨论

 

 

 

 

posted @ 2012-05-17 15:52  hi_bazinga  阅读(2724)  评论(0编辑  收藏  举报