一、准备

在开始编写代码之前,我们需要思考一下:用户登陆模块,实现的是什么功能?很明显,是登陆功能,那么,登陆需要用户名和密码,我们在数据库的一张表中就应该准备好用户名和密码的字段,再思考一下,如果要实现自动登陆的功能,那么还需要什么?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,以下为代码:

  1. <?php
  2. namespace app\modules\backend\models;
  3. use Yii;
  4. use yii\base\Model;
  5. /**
  6. * LoginForm is the model behind the login form.
  7. */
  8. class LoginForm extends Model
  9. {
  10. public $username;
  11. public $password;
  12. public $rememberMe = true;
  13. private $_user = false;
  14. /**
  15. * @return array the validation rules.
  16. */
  17. public function rules()<span style="white-space:pre">     </span>//①
  18. {
  19. return [
  20. // username and password are both required
  21. [['username', 'password'], 'required','message'=>""],
  22. // rememberMe must be a boolean value
  23. ['rememberMe', 'boolean'],
  24. // password is validated by validatePassword()
  25. ['password', 'validatePassword'],
  26. ];
  27. }
  28. /**
  29. * Validates the password.
  30. * This method serves as the inline validation for password.
  31. *
  32. * @param string $attribute the attribute currently being validated
  33. * @param array $params the additional name-value pairs given in the rule
  34. */
  35. public function validatePassword($attribute, $params)
  36. {
  37. if (!$this->hasErrors()) {
  38. $user = $this->getUser();
  39. if (!$user || !$user->validatePassword($this->password)) {
  40. $this->addError($attribute, 'Incorrect username or password.');
  41. }
  42. }
  43. }
  44. /**
  45. * Logs in a user using the provided username and password.
  46. * @return boolean whether the user is logged in successfully
  47. */
  48. public function login()
  49. {
  50. if ($this->validate()) {
  51. if($this->rememberMe)
  52. {
  53. $this->_user->generateAuthKey();//③
  54. }
  55. return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600*24*30 : 0);
  56. }
  57. return false;
  58. }
  59. /**
  60. * Finds user by [[username]]
  61. *
  62. * @return User|null
  63. */
  64. public function getUser()
  65. {
  66. if ($this->_user === false) {
  67. $this->_user = User::findByUsername($this->username); //②
  68. }
  69. return $this->_user;
  70. }
  71. }

该Model是根据basic模板自带的LoginForm修改而成,代码中大多有注释,这里关注以下代码:

①号代码处是rules规则,rules规则定义了填充过来的数据的规则,验证所填的数据是否为空,是否符合格式之类的,其中有一栏是password,对应的规则是validatePassword,会自动调用当前类的validatePassword()方法,注意与下文的User类对应的方法区分。

②号代码,调用了User类里面的findByUsername方法,这个User类下面会写到,主要是为了返回一个AR类实例,与当前LoginForm的数据进行比较。

③号代码,这里暂时不提,等讲到cookie登陆的时候再提。

2、User.php

(1)ActiveRecord 类

在完成LoginForm后,我们还缺少一些东西,从用户接受到数据了,那么还需要从数据库取出相应的数据来进行比较,所以我们接下来需要完成的是一个从数据库获取的数据的类——AR类,全称是ActiveRecord,活动记录类,方便用于查找数据,只要类名和数据表的表名相同,那么它就能从这个数据表中获取数据,比如说这样:

  1. <?php
  2. namespace app\modules\backend\models;
  3. use yii\db\ActiveRecord;
  4. class User extends ActiveRecord{       } ?>

此外,还能自己添加返回的表名,只要在这个类中重写以下方法:

  1. public static function tableName(){
  2. return 'user';
  3. }

(2)IdentityInterface 接口

一般来说,从数据库查找数据,只需要继承AR类即可,但是,我们这个是用户登录模型,核心是验证,所以自然需要实现核心的验证功能,就像LoginForm模型提到的validatePassword一样,实际的验证逻辑是在当前的User模型完成的。一般来说,实现IdentityInterface接口,需要实现以下方法:

  1. public static function findIdentity($id);  //①
  2. public static function findIdentityByAccessToken($token, $type = null);   //②
  3. public function getId();    //③
  4. public function getAuthKey();   //④
  5. public function validateAuthKey($authKey);    //⑤

①findIdentity:是根据id查找数据表对应的数据

②findIdentityByAccessToken是根据AccessToken(上文提到的)查找对应的数据,而AccessToken我们在数据表也有这个字段,那么它到底有什么用呢?其实AccessToken在我们当前的用户登陆模型中用处并不大,它是专门用于Resetful登陆验证用到的,具体可自行百度,这里不展开说明。

③getId:返回当前AR类所对应的id

④getAuthKey:返回当前AR类所对应的auth_key

⑤validateAuthKey:这个方法比较重要,是我们后面要讲到的cookie登陆验证的核心所在。

好了,既然知道了这五个方法的用处,那么我们在我们的User.php实现接口,然后重写以上方法,完整的User.php的代码如下:

  1. <?php
  2. namespace app\modules\backend\models;
  3. use yii\db\ActiveRecord;
  4. class User extends ActiveRecord implements \yii\web\IdentityInterface
  5. {
  6. public static function tableName(){
  7. return 'user';
  8. }
  9. public static function findIdentity($id){
  10. return static::findOne($id);
  11. }
  12. public static function findIdentityByAccessToken($token,$type=null){
  13. return static::findOne(['accessToken'=>$token]);
  14. }
  15. public static function findByUsername($username){     //①
  16. return static::findOne(['username'=>$username]);
  17. }
  18. public function getId(){
  19. return $this->id;
  20. }
  21. public function getAuthkey(){
  22. return $this->auth_key;
  23. }
  24. public function validateAuthKey($authKey){
  25. return $this->auth_key === $authKey;
  26. }
  27. public function validatePassword($password){          //②
  28. return $this->password === md5($password);
  29. }
  30. <span style="white-space:pre"> </span> /**
  31. <span style="white-space:pre">    </span> * Generates "remember me" authentication key
  32. <span style="white-space:pre">    </span> */
  33. public function generateAuthKey()                    //③
  34. {
  35. <span style="white-space:pre">     </span>$this->auth_key = \Yii::$app->security->generateRandomString();
  36. <span style="white-space:pre">     </span>$this->save();
  37. }
  38. }
  39. ?>

这里分析其中的三个方法:

①findByUsername():在LoginForm的代码中,引用了这个方法,目的是根据用户提交的username返回一个在数据表与username相同的数据项,即AR实例。

②validatePassword():这里对用户提交的密码以及当前AR类的密码进行比较。

③generateAuthKey():生成随机的auth_key,用于cookie登陆。

到此,我们完成了Model的编写,一共写了两个Model类:LoginForm和User,一个用于接收用户提交的数据,一个用于获取数据库的数据,接下来我们编写Controller.

三、控制器(Controller)

控制器,主要是用于数据的提交,把用户提交的数据填充到相应的模型(Model)中,然后根据模型返回的信息进一步渲染视图(View),或者执行其他逻辑。

这里,把控制器命名为LoginController.php,以下是完整的实现代码:

  1. <?php
  2. namespace app\controllers;
  3. use Yii;
  4. use yii\filters\AccessControl;
  5. use yii\web\Controller;
  6. use yii\filters\VerbFilter;
  7. use app\models\LoginForm;
  8. use app\models\ContactForm;
  9. class SiteController extends Controller
  10. {
  11. public function actionIndex()
  12. {
  13. return $this->render('index');
  14. }
  15. public function actionLogin()
  16. {
  17. if (!\Yii::$app->user->isGuest) {     //①
  18. return $this->goHome();
  19. }
  20. $model = new LoginForm();             //②
  21. if ($model->load(Yii::$app->request->post()) && $model->login()) {      //③
  22. return $this->goBack();          //④
  23. }
  24. return $this->render('login', [      //⑤
  25. 'model' => $model,
  26. ]);
  27. }
  28. public function actionLogout()
  29. {
  30. Yii::$app->user->logout();
  31. return $this->goHome();
  32. }
  33. }

关注其中的actionLogin()方法:

①首先从\Yii::$app->user->isGuest中判断,当前是否是游客模式,即未登陆状态,如果用户已经登陆,会在user类中储存当前登陆用户的信息。

②如果当前是游客,会先实例化一个LoginForm模型

③这行代码是整个login方法的核心所在,首先:$model->load(Yii::$app->request->post())把post过来的数据填充进$model,即LoginForm模型,如果返回true,则填充成功。接着:$model->login():执行LoginForm类里面的login()方法,可以从login()方法里面看到,将会执行一系列的验证。

关于Yii框架到底是怎样进行用户登陆的,底层是怎样实现的,我们在下一篇文章详谈,这里先说明实现方法。

四、视图(View)

在实现了model和controller,接下来是视图部分,由于用户需要输入数据,所以我们要提供一个表单,在Yii2中,提供了ActiveForm快速生成表单,代码如下:

  1. <?php
  2. /* @var $this yii\web\View */
  3. /* @var $form yii\bootstrap\ActiveForm */
  4. /* @var $model app\models\LoginForm */
  5. use yii\helpers\Html;
  6. use yii\bootstrap\ActiveForm;
  7. $this->title = 'Login';
  8. $this->params['breadcrumbs'][] = $this->title;
  9. ?>
  10. <div class="site-login">
  11. <h1><?= Html::encode($this->title) ?></h1>
  12. <p>Please fill out the following fields to login:</p>
  13. <?php $form = ActiveForm::begin([
  14. 'id' => 'login-form',
  15. 'options' => ['class' => 'form-horizontal'],
  16. 'fieldConfig' => [
  17. 'template' => "{label}\n<div class=\"col-lg-3\">{input}</div>\n<div class=\"col-lg-8\">{error}</div>",
  18. 'labelOptions' => ['class' => 'col-lg-1 control-label'],
  19. ],
  20. ]); ?>
  21. <?= $form->field($model, 'username')->textInput(['autofocus' => true]) ?>
  22. <?= $form->field($model, 'password')->passwordInput() ?>
  23. <?= $form->field($model, 'rememberMe')->checkbox([
  24. 'template' => "<div class=\"col-lg-offset-1 col-lg-3\">{input} {label}</div>\n<div class=\"col-lg-8\">{error}</div>",
  25. ]) ?>
  26. <div class="form-group">
  27. <div class="col-lg-offset-1 col-lg-11">
  28. <?= Html::submitButton('Login', ['class' => 'btn btn-primary', 'name' => 'login-button']) ?>
  29. </div>
  30. </div>
  31. <?php ActiveForm::end(); ?>
  32. <div class="col-lg-offset-1" style="color:#999;">
  33. You may login with <strong>admin/admin</strong> or <strong>demo/demo</strong>.<br>
  34. To modify the username/password, please check out the code <code>app\models\User::$users</code>.
  35. </div>
  36. </div>

$form=ActiveForm::begin() :创建一个Form表单

$form=field()->textInput()   :创建一个文本输入框

$form=field()->checkbox() :创建一个checkbox

Html::submitButton():          创建一个登陆按钮

ActiveForm::end()    :   结束表单

以上,就是创建一个用户登陆模块的全流程,这里对用户登陆的细节和怎样实现cookie自动登陆只是一笔带过,更详细的源码分析请看下一篇博文,谢谢。

ps:本文转自他人,并非原创

Yii2.0 用户登录详解(上)的更多相关文章

  1. yii2.0用户登录,退出判断(摘录)

    文章来源:http://blog.sina.com.cn/s/blog_88a65c1b0101ix13.html 判断用户是否登录 在 Yii2.0 里面,判断用户是否已经登录,我们用下面的代码即可 ...

  2. 关于NopCommerce3.6版用户登录详解

    一.登录方式 Nop登录方式有两种(且只能选择一种方式登录):一种是用用户名登录,另一种是用户注册邮箱登录,这个在后台可配置: 第一种:用户名登录 后台配置路径在商城设置à设置管理à客户设置:使用用户 ...

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

      这只是自己练习的一个记录而已. 因为某种原因,不想用yii自带的user表,想用自己建的admin数据库表,修改如下: 1. 参考高级模板里里的common\models\User 修改 Admi ...

  4. sql server 2008 数据库管理系统使用SQL语句创建登录用户步骤详解

    介绍了sql server 2008 数据库管理系统使用SQL语句创建登录用户步骤详解 --服务器角色: --固定服务器角色具有一组固定的权限,并且适用于整个服务器范围. 它们专门用于管理 SQL S ...

  5. 转 OAuth 2.0授权协议详解

    http://www.jb51.net/article/54948.htm 作者:阮一峰 字体:[增加 减小] 类型:转载 时间:2014-09-10我要评论 这篇文章主要介绍了OAuth 2.0授权 ...

  6. linux ssh使用深度解析(key登录详解)

    linux ssh使用深度解析(key登录详解) SSH全称Secure SHell,顾名思义就是非常安全的shell的意思,SSH协议是IETF(Internet Engineering Task ...

  7. SSL/TLS协议详解(上):密码套件,哈希,加密,密钥交换算法

    本文转载自SSL/TLS协议详解(上):密码套件,哈希,加密,密钥交换算法 导语 作为一名安全爱好者,我一向很喜欢SSL(目前是TLS)的运作原理.理解这个复杂协议的基本原理花了我好几天的时间,但只要 ...

  8. Linux常用命令详解上

    Linux常用命令详解上 目录 一.shell 二.Linux命令 2.1.内部命令与外部命令的区别 2.2.Linux命令行的格式 2.3.编辑Linux命令行的辅助操作 2.4.获得命令帮助的方法 ...

  9. 前后端分离,简单JWT登录详解

    前后端分离,简单JWT登录详解 目录 前后端分离,简单JWT登录详解 JWT登录流程 1. 用户认证处理 2. 前端登录 3. 前端请求处理 4. 后端请求处理 5. 前端页面跳转处理 6. 退出登录 ...

随机推荐

  1. 【转】Linux常用命令大全

    原文地址:http://www.php100.com/html/webkaifa/Linux/2009/1106/3485.html 系统信息 arch 显示机器的处理器架构(1) uname -m ...

  2. DMZ区

    DMZ是英文“Demilitarized Zone”的缩写,它是为了解决安装防火墙后外部网络不能访问内部网络服务器的问题,而设立的一个非安全系统与安全系统之间的缓冲区,这个缓冲区位于企业内部网络和外部 ...

  3. 使用FileZilla等软件搭建ftp服务器

    FTP的全称是File Transfer Protocol(文件传输协议).顾名思义,就是专门用来传输文件的协议. FTP服务器,则是在互联网上提供存储空间的计算机,它们依照FTP协议提供服务.简单地 ...

  4. 报表工具如何实现多次导入Excel

    很多人在开发报表的时候会遇到将多张表样相同的excel导入到模板,然后提交至数据库中.但问题是很多情况,在线导入不支持一次性选择多个excel,一次只能选择一个excel,也不能将多个excel中的数 ...

  5. 对象比较器:Comparable和Comparator

    在进行对象数组排序的过程中需要使用到比较器,比较器有两个:Comparable和Comparator ①.java.lang.Comparable:是在类定义是时候默认实现好的接口,里面提供有一个co ...

  6. Bean生命周期及BeanFactory

    1.spring通过BeanFactory灵活配置.管理bean,Spring对管理的bean没有任何特别的要求,完全支持对POJO的管理: 2.BeanFactory有个ApplicationCon ...

  7. [No000073]C#直接删除指定目录下的所有文件及文件夹(保留目录)

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  8. HTML 学习笔记 JavaScript (prototype)

    原博地址:http://www.cnblogs.com/dolphinX/p/3286177.html 原博客的作者是一个非常牛逼的前端大神,我作为一个初学者,在此借助大神的博客进行自己的学习.在这里 ...

  9. angular学习笔记(二十九)-$q服务

    angular中的$q是用来处理异步的(主要当然是http交互啦~). $q采用的是promise式的异步编程.什么是promise异步编程呢? 异步编程最重要的核心就是回调,因为有回调函数,所以才构 ...

  10. 解决Scala Play框架在Git Bash运行的异常:Could not find configuration file ../framework/sbt/sbt.boot.properties

    Git Bash+ConEmu可以模拟Linux强大的命令行.不过在结合Scala和Play时,需要注意如下事项: 1. Scala的安装在64位操作系统下,默认会放在“C:\Program File ...