设计

设计权限表格时,可以考虑以下字段:

  • id: 权限 ID,自增主键
  • name: 权限名称,用于标识该权限
  • slug: 权限标识符,唯一值,用于程序中进行权限校验
  • description: 权限描述,用于说明该权限的作用
  • created_at: 创建时间
  • updated_at: 更新时间
    你还可以考虑添加其他字段,如下:
  • type: 权限类型,用于区分不同类型的权限,如前台用户权限、后台管理权限等
  • module: 权限所属模块,如用户管理、订单管理等
  • url: 权限对应的 URL,用于前端菜单的权限控制
  • parent_id: 父级权限 ID,用于建立权限之间的父子关系
    具体需要添加哪些字段,还需要根据实际情况进行考虑。

同时,还需要设计一个用户与权限之间的关联表,用于记录用户拥有的权限。可以考虑以下字段:

  • id: 关联 ID,自增主键
  • user_id: 用户 ID,关联到用户表
  • permission_id: 权限 ID,关联到权限表
  • created_at: 创建时间
  • updated_at: 更新时间
    同样,你还可以添加其他字段,如下:
  • type: 权限类型,同上
  • module: 权限所属模块,同上
    以上只是建议的表结构,具体实现需要根据实际情况进行考虑和调整。

怎么才能检验是否有相关权限呢?

为了检验用户是否有权限访问某个资源,通常的做法是在用户登录时生成一个包含所有权限的 token,然后在用户每次请求时,将这个 token 发送给服务器进行验证。

具体实现可以使用 JSON Web Tokens(JWT)或其他的身份验证库来实现。在 Laravel 中,你可以使用 Laravel Passport 或者类似的库来进行身份验证和授权管理。这些库可以帮助你轻松地生成和验证 token,以及限制访问资源的权限。同时,Laravel 的路由系统也提供了方便的中间件,你可以使用它们来限制用户访问某些路由或资源。

中间件

这里是一个简单的示例代码,用于检查用户是否有访问某个路由的权限。这里假设你已经定义了一个名为 permissions 的权限表。

首先,你需要在路由定义时使用中间件来检查权限。下面是一个例子:

Route::get('/dashboard', function () {
    // 返回用户的仪表盘
})->middleware('check-permission:dashboard');

上面的代码中,check-permission 是一个自定义的中间件名,dashboard 是你要检查的权限的名称。

然后,在 app/Http/Middleware/CheckPermission.php 文件中,定义一个名为 handle 的方法,用于检查权限:

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Auth;

class CheckPermission
{
    public function handle($request, Closure $next, $permissionName)
    {
        if (! Auth::check()) {
            return redirect('/login');
        }

        $user = Auth::user();

        // 检查用户是否有访问此权限的权限
        if (! $user->hasPermission($permissionName)) {
            abort(403, 'You do not have permission to access this resource.');
        }

        return $next($request);
    }
}

上面的代码中,我们首先检查用户是否已经登录,如果没有登录则重定向到登录页面。然后,我们从 Auth::user() 中获取当前用户,并调用 hasPermission 方法来检查是否具有所需的权限。如果用户没有该权限,我们会抛出一个 403 异常。

最后,我们需要在 User 模型中定义一个 hasPermission 方法,用于检查用户是否具有指定的权限:

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;

class User extends Model
{
    public function hasPermission($permissionName)
    {
        $query = DB::table('permissions')
            ->join('role_permission', 'permissions.id', '=', 'role_permission.permission_id')
            ->join('user_role', 'role_permission.role_id', '=', 'user_role.role_id')
            ->where('user_role.user_id', '=', $this->id)
            ->where('permissions.name', '=', $permissionName);

        return $query->exists();
    }
}

上面的代码中,我们在 User 模型中定义了一个 hasPermission 方法,它会检查用户是否具有指定的权限。该方法通过将 permissionsrole_permissionuser_role 表进行连接,并查询是否存在具有给定名称的权限。如果存在,该方法返回 true,否则返回 false

注意,上面的代码仅供参考,具体实现可能因项目而异。

一个简单的权限管理表的 SQL 建表语句

CREATE TABLE `permissions` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `slug` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `description` text COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `permissions_slug_unique` (`slug`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

该表包含了 idnameslugdescriptioncreated_atupdated_at 六个字段。

其中 id 是主键,自增类型;name 是权限名称,varchar 类型;slug 是权限标识符,varchar 类型;description 是权限描述,text 类型;created_at updated_at 分别是创建时间和更新时间,timestamp 类型。

slug 字段设置为 UNIQUE 索引,保证每个权限标识符唯一。

当然,根据实际需求,可能还需要添加其他的字段,如权限类型、父级权限等。

前端鉴权

后端返回内容

{
  "routes": [
    {
      "name": "home",
      "path": "/home",
      "method": "GET",
      "permissions": ["view_home"]
    },
    {
      "name": "users",
      "path": "/users",
      "method": "GET",
      "permissions": ["view_users"]
    },
    {
      "name": "create_user",
      "path": "/users/create",
      "method": "POST",
      "permissions": ["create_user"]
    },
    {
      "name": "edit_user",
      "path": "/users/:id/edit",
      "method": "PUT",
      "permissions": ["edit_user"]
    }
  ],
  "permissions": ["view_home", "view_users", "create_user", "edit_user"]
}

前端Vue代码

<template>
  <div>
    <button v-if="can('create_user')" @click="createUser">Create User</button>
    <button v-if="can('edit_user')" @click="editUser">Edit User</button>
    <router-view></router-view>
  </div>
</template>

<script>
import axios from 'axios';

export default {
  data() {
    return {
      permissions: [],
      routes: [],
    };
  },
  created() {
    this.getPermissions();
  },
  methods: {
    getPermissions() {
      axios.get('/api/permissions').then((response) => {
        this.permissions = response.data.permissions;
        this.routes = response.data.routes;
      });
    },
    can(permission) {
      return this.permissions.includes(permission);
    },
    createUser() {
      // TODO: handle create user logic
    },
    editUser() {
      // TODO: handle edit user logic
    },
  },
};
</script>

在这个例子中,我们在created钩子中发送了一个请求,获取所有的路由和权限。然后我们将这些信息保存在Vue组件的data对象中。

我们在Vue组件中添加了一个can方法,用于检查当前用户是否拥有特定的权限。我们可以在Vue模板中使用v-if指令来根据权限来控制按钮的显示。

当用户单击“Create User”或“Edit User”按钮时,我们可以使用Vue方法来执行特定的操作。在这里,我们只是简单地添加了TODO注释,以说明这些方法需要添加其他逻辑来完成相应的任务。

这样,我们就可以在前端Vue应用程序中根据用户的权限来控制按钮的显示和操作的执行。