资讯专栏INFORMATION COLUMN

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

livem / 972人阅读

摘要:原文来自上一篇文章讲了用户的注册,验证和登录,这一篇文章按照约定来说说之中的用户和权限控制。探寻上面的一些列设置和代码更改,已经实现了一小部分的用户控制登录的用户才能发表。

  

原文来自: https://jellybool.com/post/programming-with-yii2-user-access-controls

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

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

  

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

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

权限控制

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

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


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

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

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

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

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

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里面的内容:

```


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

```
 "modules" => [
        "user" => [
            "class" => "dektriumuserModule",
            "confirmWithin" => 21600,
            // add the following 3 lines
            "modelMap" => [
                "User" => "appmodelsUser",
            ],

            "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 :

```
 $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了。

探寻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文件:

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

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

 [
                "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(删除按钮),你将会看到一个报错的页面:

我们手动创建的role是成功,但是我们怎么给一个注册的用户默认的权限呢,我们这里就是想实现在新用户注册的时候赋予用户ROLE_USER的角色和权限。由于Yii2-User是在vendordektriumyii2-usermodelsRegistrationForm.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

下一节

下一节尝试集成一个编辑器和做一下url的美化,内容应该会比较简单

Happy Hacking

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/21044.html

相关文章

  • Yii2系列教程七:Behaviors And Validations

    摘要:原文来自这一篇文章的开头就无需多言了,紧接着上一篇的内容和计划,这一篇我们来说说的和。,那既然这样,我们就来实现一下呗。所以我们首先需要将表中的几条数据删掉。下一节再详细讲讲吧,这一节写下来貌似要说的实在有点多。 原文来自:https://jellybool.com/post/programming-with-yii2-behaviors-and-validat... 这一篇...

    fasss 评论0 收藏0
  • Yii2系列教程四:实现用户注册,验证,登录

    摘要:开始使用邮箱配置好了之后,我们就可以开始使用了,首先我们来修改一下我们的导航栏,因为我们想实现的就是我们常常看到的在导航栏的右侧的注册和登录按钮。 原文来自: https://jellybool.com/post/programming-with-yii2-integrating-user-regi... 本来打算昨晚写的这篇教程,但是忙着约会去了,所以现在补上吧。 上一篇...

    boredream 评论0 收藏0
  • Yii2系列教程六:集成编辑器

    摘要:而这些问题目前的最好解决方案就是集成一个编辑器,鉴于大家这里不是指程序员都是喜欢所见即所得,所以,这里我主要是演示怎么集成所见即所得的富文本编辑器。 原文来自: https://jellybool.com/post/programming-with-yii2-rich-text-input-with-redactor 首先,很惭愧的是,前几天都出去外面玩了,没有及时更新教程,...

    xiaochao 评论0 收藏0
  • Yii2系列教程二:MVC Forms 和 Layouts

    摘要:而且很明显地,我们可以看到,一旦输入框在失去焦点的时候,如果里面没有输入任何内容,每个输入框就会有相应的错误提示,用户体验很不错。 原文来自: https://jellybool.com/post/programming-with-yii2-exploring-mvc-forms-a... 上一篇文章我们简单地实现了Yii2框架安装和Hello World,而在这一篇文章当中...

    ThreeWords 评论0 收藏0
  • yii2搭建完美后台并实现rbac权限控制实例教程

    摘要:利用渲染后台模板后台的模板我们采用利用插播一曲是一个完全响应管理模板。基于框架,易定制模板。适合多种屏幕分辨率,从小型移动设备到大型台式机。内置了多个页面,包括仪表盘邮箱日历锁屏登录及注册错误错误等页面。 作者:白狼 出处:http://www.manks.top/yii2_fra... 本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保...

    neu 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<