Yii中实现处理前后台登录的新方法


Posted in PHP onDecember 28, 2015

本文实例讲述了Yii中实现处理前后台登录的新方法。分享给大家供大家参考,具体如下:

因为最近在做一个项目涉及到前后台登录问题,我是把后台作为一个模块(Module)来处理的。我看很多人放两个入口文件index.php和admin.php,然后分别指向前台和后台。这种方法固然很好,可以将前后台完全分离,但我总觉得这种方式有点牵强,这和两个应用啥区别?还不如做两个App用一个framework更好。而且Yii官方后台使用方法也是使用Module的方式。但是Moudle的方式有一个很头疼的问题,就是在使用Cwebuser登录时会出现前后台一起登录一起退出的问题,这显然是不合理的。我纠结了很久才找到下文即将介绍的方法,当然,很多也是参考别人的,自己稍作了改动。我一开始的做法是在后台登录时设置一个isadmin的session,然后再前台登录时注销这个session,这样做只能辨别是前台登录还是后台登录,但做不到前后台一起登录,也即前台登录了后台就退出了,后台登录了前台就退出了。出现这种原因的根本原因是我们使用了同一个Cwebuser实例,不能同时设置前后台session,要解决这个问题就要将前后台使用不同的Cwebuser实例登录。下面是我的做法,首先看protected->config->main.php里对前台user(Cwebuser)的配置:

'user'=>array(
  'class'=>'WebUser',//这个WebUser是继承CwebUser,稍后给出它的代码
  'stateKeyPrefix'=>'member',//这个是设置前台session的前缀
  'allowAutoLogin'=>true,//这里设置允许cookie保存登录信息,一边下次自动登录
),

在你用Gii生成一个admin(即后台模块名称)模块时,会在module->admin下生成一个AdminModule.php文件,该类继承了CWebModule类,下面给出这个文件的代码,关键之处就在该文件,望大家仔细研究:

<?php
class AdminModule extends CWebModule
{
  public function init()
  {
    // this method is called when the module is being created
    // you may place code here to customize the module or the application
    parent::init();//这步是调用main.php里的配置文件
    // import the module-level models and componen
    $this->setImport(array(
      'admin.models.*',
      'admin.components.*',
    ));
    //这里重写父类里的组件
    //如有需要还可以参考API添加相应组件
    Yii::app()->setComponents(array(
        'errorHandler'=>array(
            'class'=>'CErrorHandler',
            'errorAction'=>'admin/default/error',
        ),
        'admin'=>array(
            'class'=>'AdminWebUser',//后台登录类实例
            'stateKeyPrefix'=>'admin',//后台session前缀
            'loginUrl'=>Yii::app()->createUrl('admin/default/login'),
        ),
    ), false);
    //下面这两行我一直没搞定啥意思,貌似CWebModule里也没generatorPaths属性和findGenerators()方法
    //$this->generatorPaths[]='admin.generators';
    //$this->controllerMap=$this->findGenerators();
  }
  public function beforeControllerAction($controller, $action)
  {
    if(parent::beforeControllerAction($controller, $action))
    {
      $route=$controller->id.'/'.$action->id;
      if(!$this->allowIp(Yii::app()->request->userHostAddress) && $route!=='default/error')
        throw new CHttpException(403,"You are not allowed to access this page.");
      $publicPages=array(
        'default/login',
        'default/error',
      );
      if(Yii::app()->admin->isGuest && !in_array($route,$publicPages))
        Yii::app()->admin->loginRequired();
      else
        return true;
    }
    return false;
  }
  protected function allowIp($ip)
  {
    if(empty($this->ipFilters))
      return true;
    foreach($this->ipFilters as $filter)
    {
      if($filter==='*' || $filter===$ip || (($pos=strpos($filter,'*'))!==false && !strncmp($ip,$filter,$pos)))
        return true;
    }
    return false;
  }
}
?>

AdminModule 的init()方法就是给后台配置另外的登录实例,让前后台使用不同的CWebUser,并设置后台session前缀,以便与前台session区别开来(他们同事存在$_SESSION这个数组里,你可以打印出来看看)。

这样就已经做到了前后台登录分离开了,但是此时你退出的话你就会发现前后台一起退出了。于是我找到了logout()这个方法,发现他有一个参数$destroySession=true,原来如此,如果你只是logout()的话那就会将session全部注销,加一个false参数的话就只会注销当前登录实例的session了,这也就是为什么要设置前后台session前缀的原因了,下面我们看看设置了false参数的logout方法是如何注销session的:

/**
* Clears all user identity information from persistent storage.
 * This will remove the data stored via {@link setState}.
 */
public function clearStates()
{
  $keys=array_keys($_SESSION);
  $prefix=$this->getStateKeyPrefix();
  $n=strlen($prefix);
  foreach($keys as $key)
  {
    if(!strncmp($key,$prefix,$n))
      unset($_SESSION[$key]);
  }
}

看到没,就是利用匹配前缀的去注销的。

到此,我们就可以做到前后台登录分离,退出分离了。这样才更像一个应用,是吧?嘿嘿…

差点忘了说明一下:

Yii::app()->user //前台访问用户信息方法
Yii::app()->admin //后台访问用户信息方法

不懂的仔细看一下刚才前后台CWebUser的配置。

附件1:WebUser.php代码:

<?php
class WebUser extends CWebUser
{
  public function __get($name)
  {
    if ($this->hasState('__userInfo')) {
      $user=$this->getState('__userInfo',array());
      if (isset($user[$name])) {
        return $user[$name];
      }
    }
    return parent::__get($name);
  }
  public function login($identity, $duration) {
    $this->setState('__userInfo', $identity->getUser());
    parent::login($identity, $duration);
  }
}
?>

附件2:AdminWebUser.php代码

<?php
class AdminWebUser extends CWebUser
{
  public function __get($name)
  {
    if ($this->hasState('__adminInfo')) {
      $user=$this->getState('__adminInfo',array());
      if (isset($user[$name])) {
        return $user[$name];
      }
    }
    return parent::__get($name);
  }
  public function login($identity, $duration) {
    $this->setState('__adminInfo', $identity->getUser());
    parent::login($identity, $duration);
  }
}
?>

附件3:前台UserIdentity.php代码

<?php
/**
 * UserIdentity represents the data needed to identity a user.
 * It contains the authentication method that checks if the provided
 * data can identity the user.
 */
class UserIdentity extends CUserIdentity
{
  /**
   * Authenticates a user.
   * The example implementation makes sure if the username and password
   * are both 'demo'.
   * In practical applications, this should be changed to authenticate
   * against some persistent user identity storage (e.g. database).
   * @return boolean whether authentication succeeds.
   */
  public $user;
  public $_id;
  public $username;
  public function authenticate()
  {
    $this->errorCode=self::ERROR_PASSWORD_INVALID;
    $user=User::model()->find('username=:username',array(':username'=>$this->username));
     if ($user)
    {
      $encrypted_passwd=trim($user->password);
      $inputpassword = trim(md5($this->password));
      if($inputpassword===$encrypted_passwd)
      {
        $this->errorCode=self::ERROR_NONE;
        $this->setUser($user);
        $this->_id=$user->id;
        $this->username=$user->username;
        //if(isset(Yii::app()->user->thisisadmin))
          // unset (Yii::app()->user->thisisadmin);
      }
      else
      {
        $this->errorCode=self::ERROR_PASSWORD_INVALID;
      }
    }
    else
    {
      $this->errorCode=self::ERROR_USERNAME_INVALID;
    }
    unset($user);
    return !$this->errorCode;
  }
  public function getUser()
  {
    return $this->user;
  }
  public function getId()
  {
    return $this->_id;
  }
  public function getUserName()
  {
    return $this->username;
  }
  public function setUser(CActiveRecord $user)
  {
    $this->user=$user->attributes;
  }
}

附件4:后台UserIdentity.php代码

<?php
/**
 * UserIdentity represents the data needed to identity a user.
 * It contains the authentication method that checks if the provided
 * data can identity the user.
 */
class UserIdentity extends CUserIdentity
{
  /**
   * Authenticates a user.
   * The example implementation makes sure if the username and password
   * are both 'demo'.
   * In practical applications, this should be changed to authenticate
   * against some persistent user identity storage (e.g. database).
   * @return boolean whether authentication succeeds.
   */
  public $admin;
  public $_id;
  public $username;
  public function authenticate()
  {
    $this->errorCode=self::ERROR_PASSWORD_INVALID;
    $user=Staff::model()->find('username=:username',array(':username'=>$this->username));
     if ($user)
    {
      $encrypted_passwd=trim($user->password);
      $inputpassword = trim(md5($this->password));
      if($inputpassword===$encrypted_passwd)
      {
        $this->errorCode=self::ERROR_NONE;
        $this->setUser($user);
        $this->_id=$user->id;
        $this->username=$user->username;
        // Yii::app()->user->setState("thisisadmin", "true");
      }
      else
      {
        $this->errorCode=self::ERROR_PASSWORD_INVALID;
      }
    }
    else
    {
      $this->errorCode=self::ERROR_USERNAME_INVALID;
    }
    unset($user);
    return !$this->errorCode;
  }
  public function getUser()
  {
    return $this->admin;
  }
  public function getId()
  {
    return $this->_id;
  }
  public function getUserName()
  {
    return $this->username;
  }
  public function setUser(CActiveRecord $user)
  {
    $this->admin=$user->attributes;
  }
}

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

PHP 相关文章推荐
通过具体程序来理解PHP里面的抽象类
Jan 28 PHP
php中根据某年第几天计算出日期年月日的代码
Feb 24 PHP
PHP 基于文件头的文件类型验证类函数
May 01 PHP
PHP中shuffle数组值随便排序函数用法
Nov 21 PHP
php使用正则表达式获取图片url的方法
Jan 16 PHP
PHP register_shutdown_function()函数的使用示例
Jun 23 PHP
PHP开发Apache服务器配置
Jul 15 PHP
php 微信开发获取用户信息如何实现
Dec 13 PHP
老生常谈PHP面向对象之命令模式(必看篇)
May 24 PHP
laravel5.4利用163邮箱发送邮件的步骤详解
Sep 22 PHP
PHP设计模式之适配器模式原理与用法分析
Apr 25 PHP
php创建类并调用的实例方法
Sep 25 PHP
Yii中CGridView实现批量删除的方法
Dec 28 #PHP
Yii基于数组和对象的Model查询技巧实例详解
Dec 28 #PHP
yii权限控制的方法(三种方法)
Dec 28 #PHP
Yii使用Captcha验证码的方法
Dec 28 #PHP
yii使用activeFileField控件实现上传文件与图片的方法
Dec 28 #PHP
yii实现使用CUploadedFile上传文件的方法
Dec 28 #PHP
Yii中Model(模型)的创建及使用方法
Dec 28 #PHP
You might like
javascript 小型动画组件与实现代码
2010/06/02 PHP
解决php接收shell返回的结果中文乱码问题
2014/01/23 PHP
PHP实现一维数组转二维数组的方法
2015/02/25 PHP
php微信公众号开发(4)php实现自定义关键字回复
2016/12/15 PHP
yii2 数据库读写分离配置示例
2017/02/10 PHP
PHP生成随机密码4种方法及性能对比
2020/12/11 PHP
解决AJAX中跨域访问出现'没有权限'的错误
2008/08/20 Javascript
JQuery遍历json数组的3种方法
2014/11/08 Javascript
js倒计时简单实现方法
2015/12/17 Javascript
利用纯Vue.js构建Bootstrap组件
2016/11/03 Javascript
js设置文字颜色的方法示例
2016/12/30 Javascript
Javascript循环删除数组中元素的几种方法示例
2017/05/18 Javascript
Vue axios 中提交表单数据(含上传文件)
2017/07/06 Javascript
JavaScript比较同一天的时间大小实例代码
2018/02/09 Javascript
JavaScript中利用Array filter() 方法压缩稀疏数组
2018/02/24 Javascript
js中如何完美的解析数据
2018/03/18 Javascript
浅谈js获取ModelAndView值的问题
2018/03/28 Javascript
vue中axios请求的封装实例代码
2019/03/23 Javascript
[01:03:36]Ti4 循环赛第三日DK vs Titan
2014/07/12 DOTA
[02:46]完美世界DOTA2联赛PWL DAY4集锦
2020/11/03 DOTA
[01:18:35]DOTA2-DPC中国联赛 正赛 Elephant vs LBZS BO3 第一场 1月29日
2021/03/11 DOTA
利用Python如何制作好玩的GIF动图详解
2018/07/11 Python
python解析多层json操作示例
2019/12/30 Python
Python实现CNN的多通道输入实例
2020/01/17 Python
python 双循环遍历list 变量判断代码
2020/05/04 Python
Dyson戴森波兰官网:Dyson.pl
2019/08/05 全球购物
C#如何允许一个类被继承但是避免这个类的方法被重载?
2015/02/24 面试题
几个判断型的面试题
2012/07/03 面试题
轻金属冶金专业毕业生自荐信
2013/11/02 职场文书
毕业证丢失证明
2014/01/15 职场文书
个人自我鉴定总结
2014/03/25 职场文书
工会优秀工作者事迹
2014/08/17 职场文书
法定代表人身份证明书
2014/09/10 职场文书
岳庙导游词
2015/02/04 职场文书
2016年暑期见闻作文
2015/11/25 职场文书
position:sticky 粘性定位的几种巧妙应用详解
2021/04/24 HTML / CSS