一、准备

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

    类的成员变量,成员函数,成员类型,以及基类中如果包含参数化的类型,那么该类就是一个类模板   1.定义 template<typename 类型形参1, typename 类型形参2,...&g ...

  2. sql server 2012 数据引擎任务调度算法解析(上)

    微软在sql server 2012版本之后,引入了新的任务调度算法,这个算法与之前的版本有一些细微的差别.我在这里试着简单描述一下,一些基本概念就不再赘述了,比如NUMA.scheduler.wor ...

  3. Java 容器(list, set, map)

    java容器类库的简化图: (虚线框表示接口, 实线框表示普通的类, 空心箭头表示特定的类实现了接口, 实心箭头表示某个类可以生成箭头所指的类对象) 继承Collection的主要有Set 和 Lis ...

  4. 防火墙防DDOS攻击的简单设置

    #Ping洪水攻击(Ping of Death) iptables -A FORWARD -p icmp --icmp-type echo-request -m limit --limit 1/s - ...

  5. linux下使用denyhosts防止ssh暴力破解

    1.DenyHosts介绍 DenyHosts是Python语言写的一个程序,它会分析sshd的日志文件(/var/log/secure),当发现重 复的攻击时就会记录IP到/etc/hosts.de ...

  6. MVC MemeberShip vs. Asp.net Identity

    参考 从Membership 到 .NET4.5 之 ASP.NET Identity Extending Identity Accounts and Implementing Role-Based ...

  7. [WPF系列]-Adorner

      简介 通常我们想对现有的控件,做些修饰时我们就会想到一个装饰模式.WPF中也提供了这样的实现思路:通过将Adorner添加到AdornerLayer中来实现装饰现有控件的效果.如图示:   本来T ...

  8. jstl中的sql:query标签获取的结果如何格式化输出

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...

  9. VMware下CentOS6.8配置GFS文件系统

    1.GFS介绍 GFS简要说明,它有两种: 1. Google文件系统:GFS是GOOGLE实现的是一个可扩展的分布式文件系统,用于大型的.分布式的.对大量数据进行访问的应用.它运行于廉价的普通硬件上 ...

  10. JavaScript获取客户端计算机硬件及系统等信息的方法

    JavaScript获取客户端计算机硬件及系统等信息的方法 JavaScript 获取客户端计算机硬件及系统信息 通过WMI来实现获取客户端计算机硬件及系统信息: function getSysInf ...