這篇文章主要介紹了詳細解讀PHP的Yii框架中登陸功能的實現,包括透過cookie實現自動登入的功能,需要的朋友可以參考下
Yii的登陸機制
Yii 產生應用程式時已經提供了最基礎的使用者登陸機制。我們用Yii 產生一個新的應用,進入protected/components 目錄,我們可以看到UserIdentity.php 文件,裡面的UserIdentity 類別裡面只有一個public 函數如下:
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; }
這個類別在components 裡面,會在應用一開始的時候就加載,用於最基礎的用戶驗證,可以看到,該函數一開始只是簡單地定義了兩個用戶demo 和admin,而密碼也只是demo 和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; }
這裡的authenticate 利用UserIdentity 類別對使用者名稱密碼進行驗證,而login 函數透過偵測使用者身分是否已經設定及錯誤碼是否為空,最後進行Yii 提供的login 函數進行登陸。 $duration 可以設定身分的有效期限。
再看Control,在siteControler 裡面有一個action 是關於登入的,就是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)); }# 的action是基於LoginForm 將POST 的表單進行驗證登陸或渲染新的登入頁面。 最後, view 的檔案是 site 資料夾的 login.php ,這就是你所看到的登陸介面了。 梳理一下,我們可以清楚地看到Yii 的使用者登陸邏輯處理,當你在login 介面輸入使用者名稱密碼之後,表單將資料POST 到site/login 的動作,loign 實例化了一個LoginForm表單模型,並根據model 裡面的validate 函數和login 函數進行登陸檢測,validate 會根據rule 的規則驗證表單數據,其中password 的驗證需要authenticate 函數,而authenticate 和login 函數的驗證都是基於UserIdentity 的authenticate 函數。所以,如果我們更改登入的邏輯,LgoinForm 和 loginaction 都可以不用修改,直接改 UserIdentity 的 authenticate 函數就基本上可以了。 以上的分析是 Yii 自動產生的關於使用者登陸的邏輯處理程式碼,看起來已經很像樣了不是嗎?但我們的系統一般要支援很多用戶訪問,在代碼裡簡單地羅列用戶名和密碼明顯是不理智的,更為成熟的當然是請數據庫來幫我們管理。假設我們在自己的資料庫裡面按下面的Mysql 語句建立一個admin 的表:
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 產生admin 的Model ,然後我們可以回到我們最初Component 裡面的UserIdentity.php 重寫authenticate 函數來實作我們自己的使用者名稱密碼驗證。為了安全起見,密碼採用兩次sha1 加密,所以將擷取的密碼兩次sha1 加密,然後在我們建立的Admin 裡面查找是否存在與表單輸入的username 對應的用戶,然後比對加密過的密碼,如果都通過後就可以把這個用戶的常用信息由setState 函數設置為Yii 的user 的用戶字段,比如$this->setState('nick', $user->nick); 這句話之後,以後可以直接透過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; }而如果你想要修改登陸的介面,那就進入view 裡面site 資料夾中的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中的用户信息包含有三个值:
$identity->getId()
$identity->getAuthKey()
$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['name']; $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 '$id' logged in from $ip via cookie.", __METHOD__); $this->afterLogin($identity, true, $duration); } } elseif ($identity !== null) { Yii::warning("Invalid auth key attempted for user '$id': $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中文网!
相关推荐:
以上是關於PHP的Yii框架中登陸功能的實現的詳細內容。更多資訊請關注PHP中文網其他相關文章!

php把负数转为正整数的方法:1、使用abs()函数将负数转为正数,使用intval()函数对正数取整,转为正整数,语法“intval(abs($number))”;2、利用“~”位运算符将负数取反加一,语法“~$number + 1”。

实现方法:1、使用“sleep(延迟秒数)”语句,可延迟执行函数若干秒;2、使用“time_nanosleep(延迟秒数,延迟纳秒数)”语句,可延迟执行函数若干秒和纳秒;3、使用“time_sleep_until(time()+7)”语句。

php字符串有下标。在PHP中,下标不仅可以应用于数组和对象,还可应用于字符串,利用字符串的下标和中括号“[]”可以访问指定索引位置的字符,并对该字符进行读写,语法“字符串名[下标值]”;字符串的下标值(索引值)只能是整数类型,起始值为0。

php除以100保留两位小数的方法:1、利用“/”运算符进行除法运算,语法“数值 / 100”;2、使用“number_format(除法结果, 2)”或“sprintf("%.2f",除法结果)”语句进行四舍五入的处理值,并保留两位小数。

判断方法:1、使用“strtotime("年-月-日")”语句将给定的年月日转换为时间戳格式;2、用“date("z",时间戳)+1”语句计算指定时间戳是一年的第几天。date()返回的天数是从0开始计算的,因此真实天数需要在此基础上加1。

在php中,可以使用substr()函数来读取字符串后几个字符,只需要将该函数的第二个参数设置为负值,第三个参数省略即可;语法为“substr(字符串,-n)”,表示读取从字符串结尾处向前数第n个字符开始,直到字符串结尾的全部字符。

方法:1、用“str_replace(" ","其他字符",$str)”语句,可将nbsp符替换为其他字符;2、用“preg_replace("/(\s|\ \;||\xc2\xa0)/","其他字符",$str)”语句。

查找方法:1、用strpos(),语法“strpos("字符串值","查找子串")+1”;2、用stripos(),语法“strpos("字符串值","查找子串")+1”。因为字符串是从0开始计数的,因此两个函数获取的位置需要进行加1处理。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

Atom編輯器mac版下載
最受歡迎的的開源編輯器

Dreamweaver Mac版
視覺化網頁開發工具

VSCode Windows 64位元 下載
微軟推出的免費、功能強大的一款IDE編輯器

SAP NetWeaver Server Adapter for Eclipse
將Eclipse與SAP NetWeaver應用伺服器整合。

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能