Yii2.0 用户登录详解(上)
一、准备
在开始编写代码之前,我们需要思考一下:用户登陆模块,实现的是什么功能?很明显,是登陆功能,那么,登陆需要用户名和密码,我们在数据库的一张表中就应该准备好用户名和密码的字段,再思考一下,如果要实现自动登陆的功能,那么还需要什么?Cookie,是专门用于自动登陆的,所以,我们的数据表可能需要准备一个字段,专门用于储存客户端登陆所生成的cookie,这样,就能通过验证客户端和服务端的cookie是否相同来进行自动登陆了。基于以上思考,我们的数据表应该包含以下字段: id(primarykey,auto_increment),username(varchar),password(varchar(32)),auth_key(varchar(32)),accessToken(varchar(32))(这个暂不解释,后文解释). 1、首先,建立一个数据库:myDatabase, 2、然后建立一张数据表:user,增加上述字段。 对于如何建数据库和建表,这里不再赘述。二、模型(Model)
Yii框架采用MVC设计模式,所以Model是一个模块的核心所在,所以我们先完成对Model的编写。
1、LoginForm.php
用户登陆模块,所提交的是username和password,所以我们要先建立一个Model,专门处理用户提交的数据,所以先新建一个LoginForm.php,以下为代码:
- <?php
- namespace appmodulesackendmodels;
- use Yii;
- use yiiaseModel;
- /**
- * LoginForm is the model behind the login form.
- */
- class LoginForm extends Model
- {
- public $username;
- public $password;
- public $rememberMe = true;
- private $_user = false;
- /**
- * @return array the validation rules.
- */
- public function rules()<span style="white-space:pre"> </span>//①
- {
- return [
- // username and password are both required
- [["username", "password"], "required","message"=>""],
- // rememberMe must be a boolean value
- ["rememberMe", "boolean"],
- // password is validated by validatePassword()
- ["password", "validatePassword"],
- ];
- }
- /**
- * Validates the password.
- * This method serves as the inline validation for password.
- *
- * @param string $attribute the attribute currently being validated
- * @param array $params the additional name-value pairs given in the rule
- */
- public function validatePassword($attribute, $params)
- {
- if (!$this->hasErrors()) {
- $user = $this->getUser();
- if (!$user || !$user->validatePassword($this->password)) {
- $this->addError($attribute, "Incorrect username or password.");
- }
- }
- }
- /**
- * Logs in a user using the provided username and password.
- * @return boolean whether the user is logged in successfully
- */
- public function login()
- {
- if ($this->validate()) {
- if($this->rememberMe)
- {
- $this->_user->generateAuthKey();//③
- }
- return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600*24*30 : 0);
- }
- return false;
- }
- /**
- * Finds user by [[username]]
- *
- * @return User|null
- */
- public function getUser()
- {
- if ($this->_user === false) {
- $this->_user = User::findByUsername($this->username); //②
- }
- return $this->_user;
- }
- }
该Model是根据basic模板自带的LoginForm修改而成,代码中大多有注释,这里关注以下代码:
①号代码处是rules规则,rules规则定义了填充过来的数据的规则,验证所填的数据是否为空,是否符合格式之类的,其中有一栏是password,对应的规则是validatePassword,会自动调用当前类的validatePassword()方法,注意与下文的User类对应的方法区分。
②号代码,调用了User类里面的findByUsername方法,这个User类下面会写到,主要是为了返回一个AR类实例,与当前LoginForm的数据进行比较。
③号代码,这里暂时不提,等讲到cookie登陆的时候再提。
2、User.php
(1)ActiveRecord 类
在完成LoginForm后,我们还缺少一些东西,从用户接受到数据了,那么还需要从数据库取出相应的数据来进行比较,所以我们接下来需要完成的是一个从数据库获取的数据的类——AR类,全称是ActiveRecord,活动记录类,方便用于查找数据,只要类名和数据表的表名相同,那么它就能从这个数据表中获取数据,比如说这样:
- <?php
- namespace appmodulesackendmodels;
- use yiidbActiveRecord;
- class User extends ActiveRecord{ } ?>
此外,还能自己添加返回的表名,只要在这个类中重写以下方法:
- public static function tableName(){
- return "user";
- }
(2)IdentityInterface 接口
一般来说,从数据库查找数据,只需要继承AR类即可,但是,我们这个是用户登录模型,核心是验证,所以自然需要实现核心的验证功能,就像LoginForm模型提到的validatePassword一样,实际的验证逻辑是在当前的User模型完成的。一般来说,实现IdentityInterface接口,需要实现以下方法:
- public static function findIdentity($id); //①
- public static function findIdentityByAccessToken($token, $type = null); //②
- public function getId(); //③
- public function getAuthKey(); //④
- public function validateAuthKey($authKey); //⑤
①findIdentity:是根据id查找数据表对应的数据
②findIdentityByAccessToken是根据AccessToken(上文提到的)查找对应的数据,而AccessToken我们在数据表也有这个字段,那么它到底有什么用呢?其实AccessToken在我们当前的用户登陆模型中用处并不大,它是专门用于Resetful登陆验证用到的,具体可自行百度,这里不展开说明。
③getId:返回当前AR类所对应的id
④getAuthKey:返回当前AR类所对应的auth_key
⑤validateAuthKey:这个方法比较重要,是我们后面要讲到的cookie登陆验证的核心所在。
好了,既然知道了这五个方法的用处,那么我们在我们的User.php实现接口,然后重写以上方法,完整的User.php的代码如下:
- <?php
- namespace appmodulesackendmodels;
- use yiidbActiveRecord;
- class User extends ActiveRecord implements yiiwebIdentityInterface
- {
- public static function tableName(){
- return "user";
- }
- public static function findIdentity($id){
- return static::findOne($id);
- }
- public static function findIdentityByAccessToken($token,$type=null){
- return static::findOne(["accessToken"=>$token]);
- }
- public static function findByUsername($username){ //①
- return static::findOne(["username"=>$username]);
- }
- public function getId(){
- return $this->id;
- }
- public function getAuthkey(){
- return $this->auth_key;
- }
- public function validateAuthKey($authKey){
- return $this->auth_key === $authKey;
- }
- public function validatePassword($password){ //②
- return $this->password === md5($password);
- }
- <span style="white-space:pre"> </span> /**
- <span style="white-space:pre"> </span> * Generates "remember me" authentication key
- <span style="white-space:pre"> </span> */
- public function generateAuthKey() //③
- {
- <span style="white-space:pre"> </span>$this->auth_key = Yii::$app->security->generateRandomString();
- <span style="white-space:pre"> </span>$this->save();
- }
- }
- ?>
这里分析其中的三个方法:
①findByUsername():在LoginForm的代码中,引用了这个方法,目的是根据用户提交的username返回一个在数据表与username相同的数据项,即AR实例。
②validatePassword():这里对用户提交的密码以及当前AR类的密码进行比较。
③generateAuthKey():生成随机的auth_key,用于cookie登陆。
到此,我们完成了Model的编写,一共写了两个Model类:LoginForm和User,一个用于接收用户提交的数据,一个用于获取数据库的数据,接下来我们编写Controller.
三、控制器(Controller)
控制器,主要是用于数据的提交,把用户提交的数据填充到相应的模型(Model)中,然后根据模型返回的信息进一步渲染视图(View),或者执行其他逻辑。
这里,把控制器命名为LoginController.php,以下是完整的实现代码:
- <?php
- namespace appcontrollers;
- use Yii;
- use yiifiltersAccessControl;
- use yiiwebController;
- use yiifiltersVerbFilter;
- use appmodelsLoginForm;
- use appmodelsContactForm;
- class SiteController extends Controller
- {
- public function actionIndex()
- {
- return $this->render("index");
- }
- 上一篇: php利用P3P头实现跨域设置cookie
- 下一篇:没有了
