Yii2系列教程五:简单的用户权限管理

时间:2022-11-09 22:38:14

上一篇文章讲了用户的注册,验证和登录,这一篇文章按照约定来说说Yii2之中的用户和权限控制。

你可以直接到Github下载源码,以便可以跟上进度,你也可以重头开始,一步一步按照这个教程来做。

鉴于本教材基于Yii2 Basic,所以对RBAC的详细讲解我后面再单独出文章来说说吧,这里主要是简单地说一说权限控制

Yii2系列教程五:简单的用户权限管理

上一篇文章所实现的功能还比较简单,可以发一条状态,但是不知道你注意到没有,如果是没有注册的用户也可以使用我们的应用(类似小微博)来发状态,这是不符合情理的。正确的做法是在用户没有注册,登录之前,我们甚至都不应该给没有注册的用户看到我们创建状态的页面,即是http://localhost:8999/status/create就不应该让游客看到,更不用说编辑和删除一条状态(status)了。

权限控制

什么是权限控制?个人觉得在一个Web应用当中,有以下几种常见的角色和权限控制:

1. 游客,也就是没有注册的用户,一般这个权限是最小的,对于一些需要登录访问的页面没有访问权限

2. 用户,这里的用户特指注册用户,注册过后的用户一般可以使用整个web应用的主要功能,比如我们这里的发表一条状态(status)

3. 作者,这个不知道确切应该使用什么名词来描述,作者是在用户注册之后的一个权限判断,比如A发表的status状态,B君不能进行编辑,删除等,反之亦然。

4. 管理员,这里的管理员通常会是应用的开发者(所有者,或者应该这么说),几乎可以说是对站点的所有权限都有

Yii2自带的权限控制默认只支持两个角色:

  1. guest(游客,没有登录的,用?表示)

  2. authenticated (登录了的,用@表示)

在这里我们需要实现的是对这两种不同的角色指定不同的访问权限,就是为他们分配不同的可以访问的控制器或者方法。

目前我们如果直接点击导航栏的Status,我们还是可以在没有登录的情况之下进行发表状态(status),所以我们需要改一下我们的代码和逻辑,Yii2在这方面的控制做得非常好,其实实现这个我们只需要修改一下StatusController.php里面的behaviors()方法而已,在这里面加入一段access设置:

public function behaviors()
{
return [
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'delete' => ['post'],
],
],
'access' => [
'class' => AccessControl::className(),
'only' => ['index','create','update','view'],
'rules' => [
// allow authenticated users
[
'allow' => true,
'roles' => ['@'],
],
// everything else is denied
],
],
];
}

加上access这一段之后,我们再次点击Status,Yii2就会将未登录的我重定向到登录页面。

而且,这个时候,一旦你登入进去,Yii会默认自动跳转到上一个url,也就是我们刚刚点击的status/index

添加映射关系

用户一旦登录进来之后,我们就可以通过下面这行代码来获取用户的id了:

Yii::$app->user->getId();

一旦用户的id获取到,我们可以做的事就很多了。这里我们先来将一条状态和用户联系起来,也就是添加用户与说说的映射关系。要实现这个目标我们需要先修改我们的数据表(体验一下当初设计数据表考虑不周全的情况):

./yii migrate/create extend_status_table_for_created_by
Yii Migration Tool (based on Yii v2.0.6) Create new migration '/Users/jellybool/Desktop/helloYii/migrations/m150806_034325_extend_status_table_for_created_by.php'? (yes|no) [no]:yes New migration created successfully.

打开对应的migration文件,编辑up()down()方法,如果你想加入数据库的事务管理功能,你可以使用safeUp()safeDown()方法

public function up()
{
$this->addColumn('{{%status}}','created_by',Schema::TYPE_INTEGER.' NOT NULL');
$this->addForeignKey('fk_status_created_by', '{{%status}}', 'created_by', '{{%user}}', 'id', 'CASCADE', 'CASCADE');
} public function down()
{
$this->dropForeignKey('fk_status_created_by','{{%status}}');
$this->dropColumn('{{%status}}','created_by');
}

我们需要为status表添加一个created_by字段,并且将它跟user表的id设为外键关系。

如果你在status表里面有一条数据记录,你需要先删除这一条记录,不然可能会报错。

执行migrate/up:

./yii migrate/up
Yii Migration Tool (based on Yii v2.0.6) Total 1 new migration to be applied:
m150806_034325_extend_status_table_for_created_by Apply the above migration? (yes|no) [no]:yes
*** applying m150806_034325_extend_status_table_for_created_by
> add column created_by integer NOT NULL to table {{%status}} ... done (time: 0.032s)
> add foreign key fk_status_created_by: {{%status}} (created_by) references {{%user}} (id) ... done (time: 0.014s)
*** applied m150806_034325_extend_status_table_for_created_by (time: 0.059s)

数据表的外键设置好之后,我们就可以来声明StatusUser的关系了,不过在开始之前需要修改一下User.php里面的内容:

<?php
namespace app\models; use dektrium\user\models\User as BaseUser; class User extends BaseUser { public function register()
{ }
}

直接将原来的User模型的代码都删掉,只需要我们上面的代码就可以了,因为我们使用了Yii2-User, 这里就是使用dektrium\user\models\User这个模型,然后修改一下我们的config/web.php,再我们之前的user中加入几行代码:

 'modules' => [
'user' => [
'class' => 'dektrium\user\Module',
'confirmWithin' => 21600,
// add the following 3 lines
'modelMap' => [
'User' => 'app\models\User',
], 'cost' => 12,
'admins' => ['admin']
],
],

这样之后,我们的User和Status的对应关系就会建立起来。

然后我们在Status.php写上以下的说明:

public function getUser()
{
return $this->hasOne(User::className(), ['id' => 'created_by']);
}

这里声明的映射关系为hasOne,也就是说,一条状态status(说说)对应一个用户(User),我们通过['id' => 'created_by']来指定外键映射。

有了Status和User的对应关系之后,我们需要在用户发表状态的时候将用户的id保存到Statuscreated_by这一个字段中,所以我们需要在StatusController中的actionCreate方法中加上一行代码:

if ($model->load(Yii::$app->request->post())) {
$model->created_by = Yii::$app->user->getId();//add this line
$model->created_at = time();
$model->updated_at = time();
if ($model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
}
}

这里需要确认的是,你需要保证create方法只能是登录进来的用户才能访问触发。

为了更好地展示一条状态stutas的信息,我们修改一下展示状态的视图文件:status/view.php :

<?= DetailView::widget([
'model' => $model,
'attributes' => [
'id',
'user.email', // add this line
'message:ntext',
'created_by', // add this line
'permissions',
'created_at',
'updated_at',
],
]) ?>

上面的user.email中的user其实是触发Status::getUser()这个方法。

这样一刷新之后,我们就可以看到创建这条状态的用户idemail了。

Yii2系列教程五:简单的用户权限管理

探寻RBAC

上面的一些列设置和代码更改,已经实现了一小部分的用户控制:登录的用户才能发表status。然而这还不能满足我们在日常使用的需求,比如我们现在怎么确定一个用户能不能对某条状态进行修改和删除?或者说,管理员的角色在哪里体现呢?现在貌似都是平等的角色,相同的权限,对于登录的用户来说。

鉴于官方文档或者很多关于Yii2 RBAC的资料都是基于Yii2 Advanced Template,而我们一开始使用的是Yii2 Basic Template,并且我们也引入Yii2-User,所以这里我们尝试来自己实现一点点的用户权限控制。

首先我们需要在User中定义一些跟角色(role)相关的规定,比如根据不同的用户角色来赋予不同的常量:

class User extends BaseUser {
const ROLE_USER = 10;
const ROLE_MODERATOR = 20;
const ROLE_ADMIN = 30; }

上面的代码写在User模型里面,这里定义了三种角色,ROLE_USERROLE_MODERATORROLE_ADMINUSER可以发表状态,MODERATOR可以修改但是不可以删除,ADMIN可以修改和删除。

然后在helloYii/目录之下创建一个components/目录,里面新建一个AccessRule.php文件:

<?php

namespace app\components;

use app\models\User;
class AccessRule extends \yii\filters\AccessRule { /**
* @inheritdoc
*/
protected function matchRole($user)
{
if (count($this->roles) === 0) {
return true;
}
foreach ($this->roles as $role) {
if ($role === '?') {
if ($user->getIsGuest()) {
return true;
}
} elseif ($role === User::ROLE_USER) {
if (!$user->getIsGuest()) {
return true;
}
// Check if the user is logged in, and the roles match
} elseif (!$user->getIsGuest() && $role === $user->identity->role) {
return true;
}
} return false;
}
}

这里就直接借用Yii2自带的\yii\filters\AccessRule来控制权限规则。但是由于Yii2-User在创建user数据表的时候并没有role这个字段,所以我们需要手动添加,你可以直接在mysql敲命令行,或者也可以通过数据库管理工具来添加。

最后更新一下我们的StatusController.php文件,这里的behaviors()方法会做出一些调整:

<?php

namespace app\controllers;

use Yii;
use app\models\Status;
use app\models\StatusSearch;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;
use yii\filters\AccessControl;
use app\components\AccessRule;
use app\models\User; /**
* StatusController implements the CRUD actions for Status model.
*/
class StatusController extends Controller
{
public function behaviors()
{
return [
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'delete' => ['post'],
],
],
'access' => [
'class' => AccessControl::className(),
// We will override the default rule config with the new AccessRule class
'ruleConfig' => [
'class' => AccessRule::className(),
],
'only' => ['index','create', 'update', 'delete'],
'rules' => [
[
'actions' => ['index','create'],
'allow' => true,
// Allow users, moderators and admins to create
'roles' => [
User::ROLE_USER,
User::ROLE_MODERATOR,
User::ROLE_ADMIN
],
],
[
'actions' => ['update'],
'allow' => true,
// Allow moderators and admins to update
'roles' => [
User::ROLE_MODERATOR,
User::ROLE_ADMIN
],
],
[
'actions' => ['delete'],
'allow' => true,
// Allow admins to delete
'roles' => [
User::ROLE_ADMIN
],
],
],
],
];
}

我们上面根据不同等级的用户赋予不同的访问权限,这时候,如果你先logout出来,再登录回去,你还是可以看到这些status,但是一旦你点击delete(删除按钮),你将会看到一个报错的页面:

Yii2系列教程五:简单的用户权限管理

我们手动创建的role是成功,但是我们怎么给一个注册的用户默认的权限呢,我们这里就是想实现在新用户注册的时候赋予用户ROLE_USER的角色和权限。由于Yii2-User是在vendor\dektrium\yii2-user\models\RegistrationForm.php这个文件里面进行创建新的用户的,我门这里只要修改一个小地方,找到register()方法:

  public function register()
{
if ($this->validate()) {
$user = $this->module->manager->createUser([
'email' => $this->email,
'username' => $this->username,
'password' => $this->password,
'role'=>10, // add this line User::ROLE_USER;
]); return $user->register();
} return false;
}

添加'role'=>10就可以了。

如果你想证明一下我们的权限是否正确,你可以手动修改数据库中的role字段的数值,然后在进行修改和删除等操作,看看是否可以正确运行。

权限控制其实可以说是Yii2的一大特色和亮点,在这里可能并没有说得很清晰,只是简单地实现了一些规则,有机会借助Yii2 Advanced Template来实现一下。

源码会放在 Github:https://github.com/JellyBool/helloYii

Yii2系列教程五:简单的用户权限管理的更多相关文章

  1. Linux系列教程(十七)——Linux权限管理之文件系统系统属性chattr权限和sudo命令

    上篇博客我们介绍了权限管理的ACL权限,通过设定 ACL 权限,我们为某个用户指定某个文件的特定权限.这篇博客我们将介绍权限管理中用的比较多的两个命令 chattr 和 sudo . 1.设定文件系统 ...

  2. MySQL系列--1&period;安装卸载与用户权限管理

    MySQL安装 1.Ubuntu18下安装MySQL sudo apt-get install mysql-server MySQL的版本为5.7.25 2.登录MySQL 采用mysql-serve ...

  3. Yii2系列教程七:Behaviors And Validations

    这一篇文章的开头就无需多言了,紧接着上一篇的内容和计划,这一篇我们来说说Yii2的Behavior和Validations. Behavior 首先我们来说说Behavior,在Yii2中Behavi ...

  4. Yii2系列教程六:集成编辑器

    上一篇文章我们实现了简单的用户权限管理,至于更先进的RBAC,我后面会单独出一篇文章来说说.在这一篇文章当中,我主要想写的是在Yii2中集成一个编辑器,因为在我们的实际开发当中,一个简单的textar ...

  5. 黄聪:Microsoft Enterprise Library 5&period;0 系列教程&lpar;五&rpar; Data Access Application Block

    原文:黄聪:Microsoft Enterprise Library 5.0 系列教程(五) Data Access Application Block 企业库数据库访问模块通过抽象工厂模式,允许用户 ...

  6. CRL快速开发框架系列教程五&lpar;使用缓存&rpar;

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  7. C&num;微信公众号开发系列教程五(接收事件推送与消息排重)

    微信公众号开发系列教程一(调试环境部署) 微信公众号开发系列教程一(调试环境部署续:vs远程调试) C#微信公众号开发系列教程二(新手接入指南) C#微信公众号开发系列教程三(消息体签名及加解密) C ...

  8. Android Studio系列教程五--Gradle命令详解与导入第三方包

    Android Studio系列教程五--Gradle命令详解与导入第三方包 2015 年 01 月 05 日 DevTools 本文为个人原创,欢迎转载,但请务必在明显位置注明出处!http://s ...

  9. NGUI系列教程五(角色信息跟随)

    在一些网络游戏中,我们常常可以看到角色的上方显示着角色的名称,等级,血量等信息.它们可以跟随角色移动,并且可以显示和隐藏.今天我们就来学习一下这些功能的实现方法.1. 新建unity工 程,导入NGU ...

随机推荐

  1. html嵌入样式表

    1.针对文件中的字体还有属性进行设置主要设置文字的大小及其颜色问题,未涉及div飘操作 处理页面CSS 先检测该内容部分是否已经设定了样式,如果没有单独设定再按照总体设计进行限定. eg:  h1 h ...

  2. c&num;-二分查找-算法

    折半搜索,也称二分查找算法.二分搜索,是一种在有序数组中查找某一特定元素的搜索算法. A 搜素过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜素过程结束: B 如果某一特定元素大于或者小 ...

  3. &lbrack;转&rsqb;NHibernate之旅&lpar;11&rpar;:探索多对多关系及其关联查询

    本节内容 多对多关系引入 多对多映射关系 多对多关联查询 1.原生SQL关联查询 2.HQL关联查询 3.Criteria API关联查询 结语 多对多关系引入 让我们再次回顾在第二篇中建立的数据模型 ...

  4. Create-React-App项目外使用它的eslint配置

    概述 使用Create-React-App脚手架感觉它的eslint配置有点好用,于是考虑不用Create-React-App脚手架该怎么使用这些配置. 我于是eject了Create-React-A ...

  5. 使用in ()进行批量删除

    public bool DeleteList(string idlist ) { StringBuilder strSql=new StringBuilder(); strSql.Append(&qu ...

  6. mysql技术内幕之常规使用

    mysql中:终止语句方法: 1.在语句结尾处,输入分号(:)表示语句到此结束 2.使用\g(意思是go) \G以垂直的方式显示结果,每行显示一个值 数据库:数据库中包含表,对表中数据执行插入,检索, ...

  7. JWT 理解

    概念: JWT是json web token缩写.它将用户信息加密到token里,服务器不保存任何用户信息.服务器通过使用保存的密钥验证token的正确性,只要正确即通过验证. 优点是在分布式系统中, ...

  8. android学习中遇到的错误

    1.运行项目的时候报错: [2013-12-16 17:59:22 - Dex Loader] Unable to execute dex: java.nio.BufferOverflowExcept ...

  9. gitlab 启用HTTPS

    NGINX设置 启用HTTPS 警告 Nginx配置会告诉浏览器和客户端,只需在未来24个月通过安全连接与您的GitLab实例进行通信.通过启用HTTPS,您需要至少在24个月内为您的实例提供安全连接 ...

  10. docker 下 mysql 集群的搭建

    下载程序&&创建docker容器 从mysql官网https://dev.mysql.com/downloads/cluster/上下载mysql集群库mysql-cluster-gp ...