>백엔드 개발 >PHP 튜토리얼 >PHP Yii 프레임워크의 로그인 기능 구현에 대해

PHP Yii 프레임워크의 로그인 기능 구현에 대해

不言
不言원래의
2018-06-15 16:10:001315검색

이 글에서는 주로 쿠키를 통한 자동 로그인 기능을 포함하여 Yii 프레임워크의 로그인 기능 구현에 대한 자세한 해석을 소개합니다. 도움이 필요한 친구는

Yii의 로그인 메커니즘

Yii을 참조할 수 있습니다. 애플리케이션을 생성할 때 가장 기본적인 사용자 로그인 메커니즘입니다. Yii를 사용하여 새 애플리케이션을 생성하고 protected/comComponents 디렉토리에 들어갑니다. UserIdentity.php 파일을 볼 수 있습니다. 내부의 UserIdentity 클래스에는 다음과 같은 공용 함수가 하나만 있습니다.

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

이 클래스는 구성 요소에 있습니다. 가장 기본적인 사용자 인증을 위해 애플리케이션 시작 부분에 로드됩니다. 이 함수는 처음에 두 명의 사용자 데모와 admin을 정의하고 비밀번호는 데모와 admin만 정의하는 것을 볼 수 있습니다. 사용자 수는 매우 제한되어 있으므로 여기에서 사용자를 직접 수정하고 추가할 수 있습니다. 많은 경우 이에 대해 나중에 설명하겠습니다. 함수 아래의 if else는 사용자 이름과 비밀번호가 유효한지 확인하는 데 사용됩니다. 오류가 발생하면 ERROR_USERNAME_INVALID 및 ERROR_PASSWORD_INVALID가 생성됩니다. 일반적으로 실제 사용자 이름과 비밀번호 확인이 여기서 이루어지며 로그인 후 기본적인 논리적 처리가 수행됩니다.
이 클래스만 보면 로그인 제어 과정을 볼 수 없습니다. Model/Control/View의 원칙에 따라 이 세 가지 측면에 로그인 프로세스가 반영된 것을 볼 수 있습니다. 먼저 Models 폴더에 들어가면 LoginForm 클래스 파일을 볼 수 있습니다. 이 클래스는 CFormModel을 상속하며 로그인 데이터와 비즈니스 로직을 캡슐화하는 양식 모델의 파생 클래스입니다. 핵심 기능은 다음과 같습니다.

/** 
 * Authenticates the password. 
 * This is the 'authenticate' validator as declared in rules(). 
 */ 
public function authenticate($attribute,$params) 
{ 
  $this->_identity=new UserIdentity($this->username,$this->password); 
  if(!$this->_identity->authenticate()) 
    $this->addError('password','用户名或密码错误'); 
} 
 
/** 
 * Logs in the user using the given username and password in the model. 
 * @return boolean whether login is successful 
 */ 
public function login() 
{ 
  if($this->_identity===null) 
  { 
    $this->_identity=new UserIdentity($this->username,$this->password); 
    $this->_identity->authenticate(); 
  } 
  if($this->_identity->errorCode===UserIdentity::ERROR_NONE) 
  { 
    $duration=$this->rememberMe ? 3600*24*30 : 0; // 30 days 
    Yii::app()->user->login($this->_identity,$duration); 
    return true; 
  } 
  else 
    return false; 
}

여기서 인증은 UserIdentity 클래스를 사용하여 사용자 이름과 비밀번호를 확인하고, 로그인 기능은 사용자 ID가 설정되었는지, 오류 코드가 비어 있는지 확인하고, 마지막으로 Yii 함수에서 제공하는 로그인을 수행하여 로그인합니다. $duration은 ID의 유효 기간을 설정할 수 있습니다.
Control을 다시 살펴보면 siteControler에 로그인과 관련된 액션이 있는데 바로 actionLogin입니다. 기능은 다음과 같습니다.

/** 
 * Displays the login page 
 */ 
public function actionLogin() 
{ 
  if (!defined('CRYPT_BLOWFISH')||!CRYPT_BLOWFISH) 
    throw new CHttpException(500,"This application requires that PHP was compiled with Blowfish support for crypt()."); 
 
  $model=new LoginForm; 
 
  // if it is ajax validation request 
  if(isset($_POST['ajax']) && $_POST['ajax']==='login-form') 
  { 
    echo CActiveForm::validate($model); 
    Yii::app()->end(); 
  } 
 
  // 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)); 
}

로그인 액션은 POST의 로그인을 확인하기 위한 LoginForm을 기반으로 합니다. 새로운 로그인 페이지를 형성하거나 렌더링합니다.

마지막으로 사이트 폴더에 있는 login.php 파일이 바로 보이는 로그인 인터페이스입니다.

이를 정리하면 Yii의 사용자 로그인 논리 처리를 명확하게 볼 수 있습니다. 로그인 인터페이스에 사용자 이름과 비밀번호를 입력하면 양식이 사이트/로그인에 데이터를 게시하고 로그인 양식 모델을 인스턴스화합니다. 모델의 검증 기능과 로그인 기능을 기반으로 수행됩니다. Validate는 규칙의 규칙에 따라 양식 데이터를 검증합니다. UserIdentity의 인증 기능. 따라서 로그인 로직을 변경하면 LgoinForm과 loginaction을 수정할 필요가 없으며 기본적으로 UserIdentity의 인증 기능을 직접 변경하면 충분합니다.

위 분석은 Yii에서 자동으로 생성한 사용자 로그인 로직 처리 코드로 꽤 괜찮아보이죠? 그러나 우리 시스템은 일반적으로 많은 사용자의 액세스를 지원해야 합니다. 단순히 사용자 이름과 비밀번호를 코드에 나열하는 것은 분명히 비합리적입니다. 물론 데이터베이스에 관리를 요청하는 것이 더 성숙합니다. 다음 Mysql 문에 따라 자체 데이터베이스에 관리 테이블을 생성한다고 가정합니다.

drop table if exists `admin`; 
create table `admin` ( 
  `admin_id` int unsigned not null auto_increment comment '主键', 
  `username` varchar(32) not null comment '登录名', 
  `psw` char(40) not null comment '登录密码(两次sha1)', 
  `nick` varchar(64) not null comment '昵称', 
  `add_time` datetime not null comment '创建时间', 
  `login_time` datetime null comment '最近登录时间', 
  unique key(`username`), 
  primary key (`admin_id`) 
) engine=innodb default charset=utf8 comment='管理员表';

Mysql 테이블 생성이 완료된 후 gii를 사용하여 관리 모델을 생성한 다음 UserIdentity로 돌아갈 수 있습니다. 원래 구성 요소 .php 인증 기능을 다시 작성하여 자체 사용자 이름과 비밀번호 확인을 구현합니다. 보안상의 이유로 비밀번호를 sha1로 두 번 암호화하므로 수집된 비밀번호도 sha1로 두 번 암호화한 후, 우리가 생성한 Admin에서 폼에 입력한 사용자 이름에 해당하는 사용자가 있는지 찾아 비교합니다. 모든 것이 통과된 후, $this->setState('nick', $user->nick);와 같은 setState 함수를 사용하여 사용자의 공통 정보를 Yii 사용자의 사용자 필드로 설정할 수 있습니다. 문장에서 Yii:app()->user->nick을 사용하면 데이터베이스에 쿼리하지 않고도 현재 로그인된 사용자의 닉네임에 직접 액세스할 수 있습니다. 그리고 $user->login_time = date('Y-m-d H:i:s'); 사용자 로그인 시간을 업데이트하고 다음 문장에서 save를 통해 데이터베이스에 저장합니다.

public function authenticate() 
{ 
  if(strlen($this->password) > 0) 
    $this->password = sha1(sha1($this->password)); 
  $user = Admin::model()->findByAttributes(array('username' => $this->username)); 
  if($user == null) 
    $this->errorCode=self::ERROR_USERNAME_INVALID; 
  elseif( !($user instanceof Admin) || ($user->psw != $this->password) ) 
    $this->errorCode=self::ERROR_PASSWORD_INVALID; 
  else 
  { 
    $this->setState('admin_id', $user->admin_id); 
    $this->setState('nick', $user->nick); 
    $this->setState('username', $user->username); 
    $user->login_time = date('Y-m-d H:i:s'); 
    $user->save(); 
    $this->errorCode=self::ERROR_NONE; 
  } 
  return !$this->errorCode; 
}

로그인 인터페이스를 수정하려면 뷰의 사이트 폴더에 있는 login.php로 이동하여 원하는 대로 만들어서 자체 로그인을 가질 수 있도록 하세요. 프로세스도 완료되었습니다. Yii가 있으면 참 편리하지 않나요~

设置自动登陆
自动登录的原理很简单。主要就是利用cookie来实现的
在第一次登录的时候,如果登录成功并且选中了下次自动登录,那么就会把用户的认证信息保存到cookie中,cookie的有效期为1年或者几个月。

在下次登录的时候先判断cookie中是否存储了用户的信息,如果有则用cookie中存储的用户信息来登录,

配置User组件

首先在配置文件的components中设置user组件

    'user' => [
      'identityClass' => 'app\models\User',
      'enableAutoLogin' => true,
    ],

我们看到enableAutoLogin就是用来判断是否要启用自动登录功能,这个和界面上的下次自动登录无关。
只有在enableAutoLogin为true的情况下,如果选择了下次自动登录,那么就会把用户信息存储起来放到cookie中并设置cookie的有效期为3600*24*30秒,以用于下次登录

现在我们来看看Yii中是怎样实现的。

一、第一次登录存cookie

1、login 登录功能

  public function login($identity, $duration = 0)
  {
    if ($this->beforeLogin($identity, false, $duration)) {
      $this->switchIdentity($identity, $duration);
      $id = $identity->getId();
      $ip = Yii::$app->getRequest()->getUserIP();
      Yii::info("User '$id' logged in from $ip with duration $duration.", __METHOD__);
      $this->afterLogin($identity, false, $duration);
    }

    return !$this->getIsGuest();
  }

在这里,就是简单的登录,然后执行switchIdentity方法,设置认证信息。

2、switchIdentity设置认证信息

  public function switchIdentity($identity, $duration = 0)
  {
    $session = Yii::$app->getSession();
    if (!YII_ENV_TEST) {
      $session->regenerateID(true);
    }
    $this->setIdentity($identity);
    $session->remove($this->idParam);
    $session->remove($this->authTimeoutParam);
    if ($identity instanceof IdentityInterface) {
      $session->set($this->idParam, $identity->getId());
      if ($this->authTimeout !== null) {
        $session->set($this->authTimeoutParam, time() + $this->authTimeout);
      }
      if ($duration > 0 && $this->enableAutoLogin) {
        $this->sendIdentityCookie($identity, $duration);
      }
    } elseif ($this->enableAutoLogin) {
      Yii::$app->getResponse()->getCookies()->remove(new Cookie($this->identityCookie));
    }
  }

这个方法比较重要,在退出的时候也需要调用这个方法。

这个方法主要有三个功能
设置session的有效期
如果cookie的有效期大于0并且允许自动登录,那么就把用户的认证信息保存到cookie中
如果允许自动登录,删除cookie信息。这个是用于退出的时候调用的。退出的时候传递进来的$identity为null

  protected function sendIdentityCookie($identity, $duration)
  {
    $cookie = new Cookie($this->identityCookie);
    $cookie->value = json_encode([
      $identity->getId(),
      $identity->getAuthKey(),
      $duration,
    ]);
    $cookie->expire = time() + $duration;
    Yii::$app->getResponse()->getCookies()->add($cookie);
  }

存储在cookie中的用户信息包含有三个值:

  1. $identity->getId()

  2. $identity->getAuthKey()

  3. $duration

getId()和getAuthKey()是在IdentityInterface接口中的。我们也知道在设置User组件的时候,这个User Model是必须要实现IdentityInterface接口的。所以,可以在User Model中得到前两个值,第三值就是cookie的有效期。

二、自动从cookie登录

从上面我们知道用户的认证信息已经存储到cookie中了,那么下次的时候直接从cookie里面取信息然后设置就可以了。

1、AccessControl用户访问控制

Yii提供了AccessControl来判断用户是否登录,有了这个就不需要在每一个action里面再判断了 

 public function behaviors()
  {
    return [
      'access' => [
        'class' => AccessControl::className(),
        'only' => ['logout'],
        'rules' => [
          [
            'actions' => ['logout'],
            'allow' => true,
            'roles' => ['@'],
          ],
        ],
      ],
    ];
  }

2、getIsGuest、getIdentity判断是否认证用户

isGuest是自动登录过程中最重要的属性。
在上面的AccessControl访问控制里面通过IsGuest属性来判断是否是认证用户,然后在getIsGuest方法里面是调用getIdentity来获取用户信息,如果不为空就说明是认证用户,否则就是游客(未登录)。

 public function getIsGuest($checkSession = true)
  {
    return $this->getIdentity($checkSession) === null;
  }
  public function getIdentity($checkSession = true)
  {
    if ($this->_identity === false) {
      if ($checkSession) {
        $this->renewAuthStatus();
      } else {
        return null;
      }
    }

    return $this->_identity;
  }

3、renewAuthStatus 重新生成用户认证信息

 protected function renewAuthStatus()
  {
    $session = Yii::$app->getSession();
    $id = $session->getHasSessionId() || $session->getIsActive() ? $session->get($this->idParam) : null;

    if ($id === null) {
      $identity = null;
    } else {
      /** @var IdentityInterface $class */
      $class = $this->identityClass;
      $identity = $class::findIdentity($id);
    }

    $this->setIdentity($identity);

    if ($this->authTimeout !== null && $identity !== null) {
      $expire = $session->get($this->authTimeoutParam);
      if ($expire !== null && $expire < time()) {
        $this->logout(false);
      } else {
        $session->set($this->authTimeoutParam, time() + $this->authTimeout);
      }
    }

    if ($this->enableAutoLogin) {
      if ($this->getIsGuest()) {
        $this->loginByCookie();
      } elseif ($this->autoRenewCookie) {
        $this->renewIdentityCookie();
      }
    }
  }

这一部分先通过session来判断用户,因为用户登录后就已经存在于session中了。然后再判断如果是自动登录,那么就通过cookie信息来登录。

4、通过保存的Cookie信息来登录 loginByCookie

 protected function loginByCookie()
  {
    $name = $this->identityCookie[&#39;name&#39;];
    $value = Yii::$app->getRequest()->getCookies()->getValue($name);
    if ($value !== null) {
      $data = json_decode($value, true);
      if (count($data) === 3 && isset($data[0], $data[1], $data[2])) {
        list ($id, $authKey, $duration) = $data;
        /** @var IdentityInterface $class */
        $class = $this->identityClass;
        $identity = $class::findIdentity($id);
        if ($identity !== null && $identity->validateAuthKey($authKey)) {
          if ($this->beforeLogin($identity, true, $duration)) {
            $this->switchIdentity($identity, $this->autoRenewCookie ? $duration : 0);
            $ip = Yii::$app->getRequest()->getUserIP();
            Yii::info("User &#39;$id&#39; logged in from $ip via cookie.", __METHOD__);
            $this->afterLogin($identity, true, $duration);
          }
        } elseif ($identity !== null) {
          Yii::warning("Invalid auth key attempted for user &#39;$id&#39;: $authKey", __METHOD__);
        }
      }
    }
  }

先读取cookie值,然后$data = json_decode($value, true);反序列化为数组。

这个从上面的代码可以知道要想实现自动登录,这三个值都必须有值。另外,在User Model中还必须要实现findIdentity、validateAuthKey这两个方法。

登录完成后,还可以再重新设置cookie的有效期,这样便能一起有效下去了。

 $this->switchIdentity($identity, $this->autoRenewCookie ? $duration : 0);

三、退出 logout

 public function logout($destroySession = true)
  {
    $identity = $this->getIdentity();
    if ($identity !== null && $this->beforeLogout($identity)) {
      $this->switchIdentity(null);
      $id = $identity->getId();
      $ip = Yii::$app->getRequest()->getUserIP();
      Yii::info("User '$id' logged out from $ip.", __METHOD__);
      if ($destroySession) {
        Yii::$app->getSession()->destroy();
      }
      $this->afterLogout($identity);
    }

    return $this->getIsGuest();
  }


  public function switchIdentity($identity, $duration = 0)
  {
    $session = Yii::$app->getSession();
    if (!YII_ENV_TEST) {
      $session->regenerateID(true);
    }
    $this->setIdentity($identity);
    $session->remove($this->idParam);
    $session->remove($this->authTimeoutParam);
    if ($identity instanceof IdentityInterface) {
      $session->set($this->idParam, $identity->getId());
      if ($this->authTimeout !== null) {
        $session->set($this->authTimeoutParam, time() + $this->authTimeout);
      }
      if ($duration > 0 && $this->enableAutoLogin) {
        $this->sendIdentityCookie($identity, $duration);
      }
    } elseif ($this->enableAutoLogin) {
      Yii::$app->getResponse()->getCookies()->remove(new Cookie($this->identityCookie));
    }
  }

退出的时候先把当前的认证设置为null,然后再判断如果是自动登录功能则再删除相关的cookie信息。

以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!

相关推荐:

如何实现修改yii2.0用户登录使用的user表为其它的表

关于php向访客和爬虫显示不同的内容代码

위 내용은 PHP Yii 프레임워크의 로그인 기능 구현에 대해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.