1. 用户认证体系基本概念及实现;
相关概念:
-
认证: 鉴定用户身份的过程。它通常使用一个标识符(如用户名或电子邮件地址)和一个加密令牌(比如密码或者存取令牌)来鉴别用户身份
-
认证是登录功能的基础
认证框架:
-
相关组件:该框架连接了不用的组件以支持登录。欲使用这个框架,主要需要做一下工作
-
设置用户组件 yii\web\User;
-
要想使用组件,需要创建一个类实现 yii\web\IdentityInterface 接口,再连接 yii\web\User 组件,就可以实现登录、退出过程的操作
用户组件
yii\web\User
:
-
用来管理用户的认证状态(登录、退出、获取用户信息)
-
需要制定一个含有实际认证逻辑的认证类继承实现 yii\web\IdentityInterface 接口,实现以后再去连接 yii\web\User 组件,去完成认证服务
-
为什么有了 yii\web\User 组件,为什么还要去实现一个逻辑,再去连接组件?yii\web\User 组件只是提供了一个基本的框架,但是具体的实现逻辑需要按照具体的业务逻辑去实现,每个 Web 应用的认证逻辑都是不一样的。所以需要去实现延展 yii\web\IdentityInterface 这个接口(规范)。实现之后再连接组件,才能提供服务。
-
实现后的实例作为 yii\web\User 组件的身份验证实例。
认证接口
yii\web\IdentityInterface
需要实现的方法
-
yii\web\IdentityInterface::
findIdentity()
:根据用户的 id 查找认证模型类的实例,当使用 session 来维持登录状态的时候,会用到这个方法
-
yii\web\IdentityInterface::
findIdentityByAccessToken()
:根据 AccessToken 的值来获取用户认证实例。通常 AccessToken 和用户是进行邦定的,这种一般运用在无状态的 RESTful 这样的应用下
-
yii\web\IdentityInterface::
getId()
:获取用户认证实例 id
-
yii\web\IdentityInterface::
getAuthKey()
:获取基于 cookie 登录时的一个认证秘钥
-
yii\web\IdentityInterface::
ValidateAuthKey()
:认证 cookie 登录秘钥的内容
-
不一定所有的方法都要实现,不实现的方法可以留空
实例
-
实例页面:
http://192.168.2.214/yii22/basic/web/index.php?r=site/login
$config = [
'components' => [
'user' => [
'identityClass' => 'app\models\User',
'enableAutoLogin' => true,
],
],
];
class User extends \yii\base\BaseObject implements \yii\web\IdentityInterface{}
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();
}
$model->password = '';
return $this->render('login', [
'model' => $model,
]);
}
public function login(){
if ($this->validate()) {
return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600*24*30 : 0);
}
return false;
}
总结用户登录流程
-
首先页面点击登录的时候,提交给了 basic/controllers/SiteController.php 的 actionLogin()
-
第一步先 new LoginForm() 实例化,调用 basic/models/LoginForm.php 里的 login() 方法,这个方法会去调用组件的 Yii::$app->user->login() 方法,把用户实例和相关内容传递进去,就会自动的往 cookie 和 session 里写入用户相关信息,保存了登录状态
-
basic/models/User.php 作用就是继承 \yii\web\IdentityInterface 接口,实现方法
-
private static $users 指定了两个用户,
-
findIdentity($id) 方法获取用户实例,user 组件会自动调用这个方法
-
findIdentityByAccessToken($token, $type = null) 根据 Token 获取用户实例
-
findByUsername( $username ) 是自己写的方法,根据用户名将用户实例返回。在 LoginForm() 里面的 getUser() 方法,用到了 findByUsername( $username ) 方法获取用户实例,在 LoginForm() 里面的 login() 方法中,传递给 user 组件里的 login() 方法
-
getId() 获取 model 实例 id
退出流程
-
页面右上角点击退出的时候,会调用 basic/controllers/SiteController.php 中的 actionLogout()
<?php
public function actionLogout(){
Yii::$app->user->logout();
return $this->goHome();
}
2. 用户认证组件 User 相关属性和方法完成前台的登录和退出;
用户组件
yii\web\User
相关属性:
-
identity:Yii::$app->user->
identity
;当前用户的身份实例,未认证用户则为 NULL
-
id:Yii::$app->user->
id
;当前用户的 id,未认证用户则为 NULL
-
isGuest:Yii::$app->user->
isGuest
;判断当前用户是否为游客(未认证)
相关方法:
-
login:将当前用户的身份登记到 yii\web\User(第一个参数传递用户实例,第二个参数为保留的登录时间)
-
‐ 登录相关属性 1:enableSession,是否启用 session 来保存会话状态,默认 true
-
‐ 相关属性 2:enableAutoLogin,是否启用自动登录,默认 true,可以在配置文件中配置
-
logout:注销用户,启用 session 时注销用户才有意义。可以传递布尔值,传递 true 会把 session 信息全部清除,传递 false 会保留会话数据
<?php
public function actionAuth(){
$model = new User;
if(Yii->$app->request->isPost){
$post = Yii->$app->request->Post();
if($model->login($post)){
%url = Yii::$app->session->getFlash('referrer');
return $this;
}
}
return $this->render("auth", ['model' => $model])
}
public function actionLogout(){
Yii->$app->session->remove('loginname');
Yii->$app->session->remove('isLogin');
if(!isset(Yii->$app->session['isLogin'])){
return $this->goBack(Yii:$app->request->referer);
}
}
public function login($data){
$this->scenario = "login";
if($this->load($data) && $this->validate()){
$lifetime = $this->rememberMe ? 24*3600 : 0;
$session = Yii::$app->session;
session_set_cookie_params($lifetime);
$session['loginname'] = $this->loginname;
$session['isLogin'] = 1;
return (bool)$session['isLogin'];
}
return false;
}
通过用户组件去完成登录操作:
-
在 basic/config/web.php 中设置(components),然后继承 \yii\web\IdentityInterface 接口,实现 5 个方法
<?php
namespace app\models;
use yii\db\ActiveRecord;
use Yii;
class User extends ActiveRecord implements \yii\web\IdentityInterface{
public static function findIdentity($id){
return static::findOne($id);
}
public static function findIdentityByAccessToken($token, $type = null){
return NULL;
}
public function getId(){
return $this->id;
}
public function getAuthKey(){
return '';
}
public function validateAuthKey($authKey){
return true;
}
public function getUser(){
return self::find()->where('username = :loginname or useremail = :loginname', [
':loginname' => $this->loginname
])->one();
}
public function login($data){
$this->scenario = "login";
if($this->load($data) && $this->validate()){
return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 24*3600 : 0);
}
return false;
}
}
登录成功后页面显示用户名:
-
不用 session,使用 user 组件返回的一些内容进行操作
<?php
use yii\helpers\Html;
use yii\bootstrap\Nav;
use yii\bootstrap\NavBar;
?>
<?php
NavBar::begin([
'options' =>[
'class' => 'top-bar animate-dropdown',
],
]);
echo Nav::widget([
'options' => ['class' => 'navbar-nav navbar-left'],
'item' => [
['label' => '首页', 'url' => ['/site/index']],
!\Yii::$app->user->isGuest ? (
['label' => '购物车', 'url' => ['/cart/index']]
) : '',
!\Yii::$app->user->isGuest ? (
['label' => '我的订单', 'url' => ['/cart/index']]
) : '',
],
]);
echo Nav::widget([
'options' => ['class' => 'navbar-nav navbar-right'],
'item' => [
\Yii::$app->user->isGuest ? (
['label' => '注册', 'url' => ['/member/auth']]
) : '',
\Yii::$app->user->isGuest ? (
['label' => '登录', 'url' => ['/member/login']]
) : '',
!\Yii::$app->user->isGuest ? (
'欢迎您回来,' . \Yii::$app->user->identity->username .
Html::a('退出', ['member/logout'])
) : '',
],
]);
NavBar::end();
?>
用户的退出操作:
-
不用清除 session,使用 user 组件的 logout() 自动清除
public function actionLogout(){
Yii->$app->user->logout();
return $this->goBack(Yii:$app->request->referer);
}
3. 过滤器 AccessControl 控制认证用户;
if(Yii->$app->user->isGuest){
return $this->redirect(['member/auth']);
}
$userid = Yii::$app->user->id;
$orders = Order::getProducts($userid);
public function behaviors(){
return [
'access' => [
'class' => \yii\filters\AccessControl::className(),
'only' => ['*'],
'except' => [],
'rules' => [
[
'allow' => false,
'action' => ['index', 'check'],
'roles' => ['?'],
],
[
'allow' => true,
'action' => ['index', 'check'],
'roles' => ['@'],
]
]
]
];
}
'user' => [
'identityClass' => 'app\models\User',
'enableAutoLogin' => true,
'loginUrl'=> ['/member/auth']
],
- 也可以把 behaviors() 提取出来单独放到一个父类里面,所有 controller 继承这个父类
<?php
namespace app\controllers;
use app\models\User;
use app\models\Product;
use Yii;
class CommonController extends Controller{
protected $actions = ['*'];
protected $except = [];
protected $mustLogin = [];
protected $verbs = [];
public function behaviors(){
return [
'access' => [
'class' => \yii\filters\AccessControl::className(),
'only' => $this->actions,
'except' => $this->except,
'rules' => [
[
'allow' => false,
'action' => empty($this->mustLogin) ? [] : $this->mustLogin,
'roles' => ['?'],
],
[
'allow' => true,
'action' => empty($this->mustLogin) ? [] : $this->mustLogin,
'roles' => ['@'],
]
]
],
'verbs' => [
'class' => \yii\filters\VerbFilter::className(),
'actions' => $this->verbs,
],
];
}
}
class XxController extends CommonController{
protected $mustLogin = ['index', 'check', 'add', 'pay', 'received'];
protected $verbs = [
'confirm' => ['post'],
];
}
4. 过滤器 VerbFilter 过滤请求方式;
VerbFilter 的作用
-
在一些方法当中,比如做了 POST 验证 Yii::$app->request->isPost,方法只能是 POST 请求,如果是 GET 请求就报错,返回一个异常
-
如果现在要用过滤器做,同样可以通过 behavior() 操作
if(!Yii::$app->request->isPost){
throw new \Exception();
}
public function behaviors(){
return [
'access' => [
'class' => \yii\filters\AccessControl::className(),
'only' => ['logout'],
'rules' => [
[
'actions' => ['logout'],
'allow' => true,
'roles' => ['@'],
],
],
],
'verbs' => [
'class' => \yii\filters\VerbFilter::className(),
'actions' => [
'logout' => ['post'],
],
],
];
}
5. 分离前后台用户认证;
6. 后台使用过滤器验证用户;
7. 哈希算法 bcrypt 对密码加密处理。
相关概念
-
数据表存储密码,一般不会存取明文,而是通过某种哈希方式对密码进行哈希化存储。
-
哈希方式:MD5,SHA1
-
但是随着现代硬件的发展,黑客可以在短时间内对 MD5 或者 SHA1 哈希化后的密码进行暴力破解。所以需要更加安全的算法。这种算法叫
bcrypt
-
Yii2 框架提供了两个方法帮助使用 bcrypt 对密码进行哈希算法
bcrypt 相关方法
-
Yii->$app->getSecurity()->generatePasswordHash($password)
:可以将用户输入的密码进行 bcrypt 哈希,然后再存储到数据表中
-
Yii->$app->getSecurity()->validatePassword($password, $hash)
:对密码验证
$this->userpass = md5($this->userpass);
$this->userpass = Yii->$app->getSecurity()->generatePasswordHash($this->userpass);
$pass = Yii->$app->getSecurity()->validatePassword($this->userpass, $data->userpass);