一、用户角色

用户与角色之间的关系是多对多:

  • 一个用户可以有多个角色;
  • 一个角色可以被分配给多个角色。

二、前期准备

(一)路由
// 查看用户角色
Route::get('userroles/:id','UserAccess/read');
// 分配角色给用户
Route::post('userroles','UserAccess/save');
// 删除用户的角色
Route::post('userrole/delete','UserAccess/delete');
(二)控制器

使用命令

php think make:controller UserAccess
(三)表
1. 用户表

创建用户表的 SQL 语句:

CREATE TABLE `think_users` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '用户编号',
  `name` varchar(255) NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;

用户表如下:
用户表.png

2. 角色表

创建角色表的 SQL 语句:

CREATE TABLE `think_role` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '编号',
  `name` varchar(255) DEFAULT NULL COMMENT '角色名称',
  `remark` varchar(255) DEFAULT NULL COMMENT '备注',
  `del_flag` tinyint(4) DEFAULT '0' COMMENT '0 表示正常,-1表示被删除',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4;

角色表如下:
角色表.png

3. 用户角色表(中间表)

创建用户角色表的 SQL 语句:

CREATE TABLE `think_user_role` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '编号',
  `user_id` int(11) NOT NULL COMMENT '用户ID',
  `role_id` int(11) NOT NULL COMMENT '角色ID',
  `create_by` varchar(255) DEFAULT NULL COMMENT '创建人',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=27 DEFAULT CHARSET=utf8mb4;

用户角色表如下:
用户角色表.png

(四)模型
1. 用户模型

使用命令:

php think make:model User

在用户模型中定义 roles 方法:

<?php
declare (strict_types = 1);

namespace app\model;

use think\Model;

class User extends Model
{
    protected $name   = 'think_users';    
    public function roles(){
        return $this->belongsToMany(Role::class,'think_user_role','role_id','user_id');
    }
}
2. 角色模型
php think make:model Role

在角色模型中定义 users 方法:

<?php
declare (strict_types = 1);

namespace app\model;

use think\Model;

class Role extends Model
{
    protected $name = 'think_role';    
    public function users(){
        return $this->belongsToMany(User::class,'think_user_role','user_id','role_id');
    }
}
3. 用户角色模型
php think make:model Access

用户角色模型:

<?php
declare (strict_types = 1);

namespace app\model;

use think\Model;
use think\model\Pivot;

class Access extends Pivot
{
    protected $name = "think_user_role"; 
    protected $autoWriteTimestamp = true;   
}

注意:中间表模型类必须继承 think\model\Pivot

三、修改控制器

<?php
declare (strict_types = 1);

namespace app\controller;

use think\Request;
use app\model\User;

class UserAccess
{
    /**
     * 分配角色给用户
     *
     * @param  \think\Request  $request
     * @return \think\Response
     */
    public function save(Request $request)
    {
        $params = $request->param();
        $user_id = $params['user_id'];
        $role_id = $params['role_id'];
        $user = User::find($user_id);
        $roles = $user->roles;
        $role_ids = $this->collectionColumn($roles,'role_id');
        if($this->isAssignRole($role_id,$role_ids)){
            return $this->setJsonResult('error',40000,'已分配该角色,无需再次分配');
        }

        if(isset($params['create_by']) && !empty($params['create_by'])){
            // 传入中间表的额外属性
            $user->roles()->attach($role_id,['create_by'=>$params['create_by']]);
        }else{
            $user->roles()->attach($role_id);
        }
        return $this->setJsonResult('success',10000,'用户授权成功',['user_id'=>$user_id,'role_id'=>$role_id]);
    }

    /**
     * 显示用户的角色
     *
     * @param  int  $id
     * @return \think\Response
     */
    public function read($id)
    {
        $user = User::find($id);
    
        $roles = $user->roles;
        // dump($roles);
        $role_name = [];
        foreach($roles as $role){
            $role_name[] = $role->name;
        }
        return $this->setJsonResult('success',10000,'操作成功',$role_name);
    }

    /**
     * 删除用户的角色
     *
     * @param  int  $id
     * @return \think\Response
     */
    public function delete(Request $request)
    {
        $params = $request->param();
        $user_id = $params['user_id']; 
        $user = User::find($user_id);
        $role_id = $params['role_id'];
        $user->roles()->detach($role_id);
        return $this->setJsonResult('success',10000,'删除用户权限成功');
    }

    public function setJsonResult($status,$code,$message='',$data=[]){
        return json([
            'status'  => $status,
            'code'    => $code,
            'message' => $message,
            'data'    => $data
        ]);
    }

    /**
     * 获取数据集合某个字段的值
     *
     * @param  object $collection, string $column
     * @return array 
     */
    public function collectionColumn($collection,$column){
        $re = [];
        foreach($collection as $val){
            $re[] = $val->pivot->$column;
        }
        return $re;
    }
    
    /**
     * 判断之前是否为该用户分配过 role_id 对应的角色
     *
     * @param  string $collection, array $role_ids
     * @return bool 
     */
    public function isAssignRole($role_id,$role_ids){
        if(in_array($role_id,$role_ids)){
            return true;
        }
        return false;
    }
}

四、测试

在之前的测试中已经为 id 为 1 的用户分配了角色,现在测试 2 号的用户角色的查看、分配与删除:

1. 查看 2 号用户的角色

调用查看用户角色的接口:
查看2号用户的角色.png
返回值的 data 属性为空。

2. 为用户分配角色

调用为用户分配角色的接口:
为2号用户分配角色.png
用户角色表如下:
2号新增角色.png
再次调用查看用户角色的接口:
分配角色后查看.png

3. 删除用户的角色

调用删除用户角色的接口:
删除用户角色.png

删除2号角色后的数据表:
用户角色表.png


Moonshadow2333
28 声望0 粉丝

征途漫漫