yiii 框架登录 判断是否是游客模式及未登录状态
原地址:http://blog.csdn.net/a553181867/article/details/50987388
最近在利用Yii 2.0框架进行项目后台的编写,遇到的第一个问题是用户登陆,包括利用cookie,session登陆等等,笔者从源码角度结合实例为各位详细解析如何编写一个完整的用户登陆模块。(笔者的本地环境是PHP 5.5+MySQL5.6)
一、准备
开始编写代码之前,我们需要思考一下:用户登陆模块,实现的是什么功能?很明显,是登陆功能,那么,登陆需要用户名和密码,我们在数据库的一张表中就应该
准备好用户名和密码的字段,再思考一下,如果要实现自动登陆的功能,那么还需要什么?Cookie,是专门用于自动登陆的,所以,我们的数据表可能需要准
备一个字段,专门用于储存客户端登陆所生成的cookie,这样,就能通过验证客户端和服务端的cookie是否相同来进行自动登陆了。基于以上思考,我
们的数据表应该包含以下字段:
二、模型(Model)
Yii框架采用MVC设计模式,所以Model是一个模块的核心所在,所以我们先完成对Model的编写。
1、LoginForm.php
用户登陆模块,所提交的是username和password,所以我们要先建立一个Model,专门处理用户提交的数据,所以先新建一个LoginForm.php,以下为代码:
- <?php
- namespace app\modules\backend\models;
- use Yii;
- use yii\base\Model;
- /**
- * 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 app\modules\backend\models;
- use yii\db\ActiveRecord;
- 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 app\modules\backend\models;
- use yii\db\ActiveRecord;
- class User extends ActiveRecord implements \yii\web\IdentityInterface
- {
- 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 app\controllers;
- use Yii;
- use yii\filters\AccessControl;
- use yii\web\Controller;
- use yii\filters\VerbFilter;
- use app\models\LoginForm;
- use app\models\ContactForm;
- class SiteController extends Controller
- {
- public function actionIndex()
- {
- return $this->render('index');
- }
- public function actionLogin()
- {
- if (!\Yii::$app->user->isGuest) { //①
- return $this->goHome();
- }
- $model = new LoginForm(); //②
- if ($model->load(Yii::$app->request->post()) && $model->login()) { //③
- return $this->goBack(); //④
- }
- return $this->render('login', [ //⑤
- 'model' => $model,
- ]);
- }
- public function actionLogout()
- {
- Yii::$app->user->logout();
- return $this->goHome();
- }
- }
关注其中的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快速生成表单,代码如下:
- <?php
- /* @var $this yii\web\View */
- /* @var $form yii\bootstrap\ActiveForm */
- /* @var $model app\models\LoginForm */
- use yii\helpers\Html;
- use yii\bootstrap\ActiveForm;
- $this->title = 'Login';
- $this->params['breadcrumbs'][] = $this->title;
- ?>
- <div class="site-login">
- <h1><?= Html::encode($this->title) ?></h1>
- <p>Please fill out the following fields to login:</p>
- <?php $form = ActiveForm::begin([
- 'id' => 'login-form',
- 'options' => ['class' => 'form-horizontal'],
- 'fieldConfig' => [
- 'template' => "{label}\n<div class=\"col-lg-3\">{input}</div>\n<div class=\"col-lg-8\">{error}</div>",
- 'labelOptions' => ['class' => 'col-lg-1 control-label'],
- ],
- ]); ?>
- <?= $form->field($model, 'username')->textInput(['autofocus' => true]) ?>
- <?= $form->field($model, 'password')->passwordInput() ?>
- <?= $form->field($model, 'rememberMe')->checkbox([
- 'template' => "<div class=\"col-lg-offset-1 col-lg-3\">{input} {label}</div>\n<div class=\"col-lg-8\">{error}</div>",
- ]) ?>
- <div class="form-group">
- <div class="col-lg-offset-1 col-lg-11">
- <?= Html::submitButton('Login', ['class' => 'btn btn-primary', 'name' => 'login-button']) ?>
- </div>
- </div>
- <?php ActiveForm::end(); ?>
- <div class="col-lg-offset-1" style="color:#999;">
- You may login with <strong>admin/admin</strong> or <strong>demo/demo</strong>.<br>
- To modify the username/password, please check out the code <code>app\models\User::$users</code>.
- </div>
- </div>
$form=ActiveForm::begin() :创建一个Form表单
$form=field()->textInput() :创建一个文本输入框
$form=field()->checkbox() :创建一个checkbox
Html::submitButton(): 创建一个登陆按钮
ActiveForm::end() : 结束表单
以上,就是创建一个用户登陆模块的全流程,这里对用户登陆的细节和怎样实现cookie自动登陆只是一笔带过,更详细的源码分析请看下一篇博文,谢谢。
yiii 框架登录 判断是否是游客模式及未登录状态的更多相关文章
- swift项目实战--微博的未登录界面的实现,和监听未登录界面两个按钮的两种实现方法
1.未登录界面的实现 微博项目中,用户不登录的话,显示的是未登录的界面.项目中TabBarVC的子控制器都是tableViewVC,所以抽取了父类,让父类判断用户是否登录,决定显示什么样的界面.loa ...
- 用户未登录或Session超时时重定向到登录页,不那么简单
在网站开发中,我们经常有这样的场景出现: 情景1:对未登录的用户或没有权限的用户,当其想访问某个受限网页时,系统要能够自动转到登录页面. 情景2:对于用session保存用户状态的情况还有这样一种 ...
- 第二百六十九节,Tornado框架-Session登录判断
Tornado框架-Session登录判断 Session需要结合cookie来实现 Session的理解 1.用户登录系统时,服务器端获取系统当前时间,进行nd5加密,得到加密后的密串 2.将密串作 ...
- 苹果手机Safari无痕浏览模式下系统登录成功但是页面不跳转
昨天下午,测试提了一个bug,问题是:在苹果手机Safari无痕浏览模式下系统登录成功但是页面不跳转. 思前想后找了半天没思路,后来经过同事的点拨,说可能是禁用了cookie之类的,反正我也没思路就顺 ...
- spring MVC使用Interceptor做用户登录判断
在任何一个项目中,我们必须要用到的就是用户登录,那么就少不了用户是否登录的判断,如果我们每一个请求都要去做一次判断,那么就会变得很麻烦,但我们复制粘贴的时候我们就要考虑我们的代码写的是不是有问题,是不 ...
- 重学 Java 设计模式:实战装饰器模式(SSO单点登录功能扩展,增加拦截用户访问方法范围场景)
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 对于代码你有编程感觉吗 很多人写代码往往是没有编程感觉的,也就是除了可以把功能按照固 ...
- ubuntu不能登录图形用户界面,游客身份可登陆,命令行可登陆
ubuntu是13.04版本,我猜其他的版本解决办法大概也一样.当开机进入登陆界面后我们输入密码后并没有进入应该进入的图形用户界面,而是进入一个命令行界面并且一闪而过又回到了登录界面,而已游客的身份却 ...
- 【转】【可用】Android 登录判断器,登录成功后帮你准确跳转到目标activity
我们在使用应用时肯定遇到过这样的情景,打开应用,并不是需要我们登录,你可以浏览应用中的大部分页面,但是当你想看某个详情页的时候,点击后突然跳转到了登录页面,好,我们输入账号密码,点击登录,登录成功,跳 ...
- Loadrunner登录判断
loadrunner判断登录是否成功,以下方法可以解决:1.利用添加检查点web_reg_find函数的方法---------------------------- lr_start_transact ...
随机推荐
- 【原】iOS学习之第三方-AFNetworking1.3.0
将 CocoaPods 安装后,按照 CocoaPods 的使用说明就可以将 AFNetworking 第三方集成到工程中,具体请看上篇博客iOS学习46之第三方CocoaPods的安装和使用(通用方 ...
- Document 按照xml格式输出
private void GetXMLDocument(Document doc) { OutputFormat format1 = new OutputFormat(" ", t ...
- font 和 text 字和文本操作
- asp.net mvc route 中新发现的小技巧
在发现这个小技巧之前,我经常被某些问题困扰,我们以博客园为例 1:是分类名称 2:是分类url 3:点击分类,进入的页面,要显示分类的名称 4:点击分类,进入的页面,要用分类相关参数 在日常web的开 ...
- 【HDU】1693 Eat the Trees
http://acm.hdu.edu.cn/showproblem.php?pid=1693 题意:n×m的棋盘求简单回路(可以多条)覆盖整个棋盘的方案,障碍格不许摆放.(n,m<=11) #i ...
- BZOJ4551: [Tjoi2016&Heoi2016]树
Description 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为1),有以下 两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标 ...
- JavaScript 页面模板引擎
var TemplateEngine = function(html, options) { var re = /<%([^%>]+)?%>/g, reExp = /(^( )?(i ...
- Spring MVC Maven 环境搭建与部署
本文简单演示了本地开发环境的搭建.项目出包.部署运行.HelloWorld,以及部分注意事项. 起初的玩法:先安装Eclipse,然后分别下载并安装Maven.spring的插件,再进行工程模式转换, ...
- Windows环境下的NodeJS+NPM+Bower安装配置步骤
Windows下的NodeJS安装是比较方便的(v0.6.0版本之后,支持windows native),只需要登陆官网(http://nodejs.org/),便可以看到首页的“INSTALL”按钮 ...
- java修改request的paramMap
最近做项目,发现要修改request的参数内容.因为想要在request的paramMap里面默认注入,modifier和modifierName,这些内容.但是这个Map是不能修改的.所以采用了如下 ...