不败君

前端萌新&初级后端攻城狮

Laravel实现RBAC权限管理

Laravel实现RBAC权限管理

2020-08-14 16:02:50

围观(4358)

一般后台都是使用 RBAC 权限管理。 例如 Laravel-admin 也是使用了 RBAC 权限管理。

RBAC 其实就是给每个用户添加一个或多个角色身份,每个角色身份拥有很多个权限,操作时验证用户的角色权限是否含有当前操作的权限。


创建数据库

数据表如下:

1.jpg


每张表的字段如下:

2.jpg


配置 Laravel

安装文档可以看这个: https://learnku.com/docs/laravel/7.x/installation/7447 本文就不说安装了。

安装完成后 打开 .env 文件。 将数据库配置填写进去:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=rbac
DB_USERNAME=root
DB_PASSWORD=root


创建模型

在项目根目录依次执行命令:

php artisan make:model Model/Auth
php artisan make:model Model/RoleAuth
php artisan make:model Model/Role
php artisan make:model Model/UserRole
php artisan make:model Model/User


创建首个后台管理员

使用命令创建控制器:

php artisan make:controller Admin/AdminCreateController

写入一个 create 方法:

public function create()
{
    $email = '123456@qq.com';
    $password = Hash::make('123456');

    $model_user = new User();
    $row_user = $model_user->getDefaultAdmin($email);
    if ($row_user) {
        // 更新
        $row_user->password = $password;
        return $row_user->save();
    }

    // 创建
    $model_user->name = $email;
    $model_user->email = $email;
    $model_user->password = $password;
    $model_user->role = User::ROLE_ADMIN;
    return $model_user->save();
}

控制器需要引入:

use Illuminate\Support\Facades\Hash;
use App\Model\User;

User 模型里面有一个 getDefaultAdmin 方法:

public function getDefaultAdmin($email = '123456@qq.com')
{
    return $this->where('email', $email)
        ->where('role', self::ROLE_ADMIN)
        ->first();
}

模型里面的常量:

const ROLE_USER = 0;        // 普通用户
const ROLE_ADMIN = 1;       // 管理员

写入路由:

Route::get('create_admin', 'Admin\AdminCreateController@create');

使用域名/create_admin访问。 页面上会显示一个 “1” 再看看数据库,已经有刚才创建的管理员了:

3.jpg


后台登录

随便写一个登录的前端页面(views/admin/login.blade.php):

<!DOCTYPE html>
<html>
<head>
    <title>不败君 RBAC 登录</title>
</head>
<body>
	<form action="{{ route('admin_login') }}" method="POST">
        @csrf
        <input type="text" name="email" placeholder="邮箱">
        <input type="password" name="password" placeholder="密码">
        <input type="submit" value="登 录">
    </form>
</body>
</html>

创建登录控制器:

php artisan make:controller Admin/AdminLoginController

写入路由:

Route::get('login', 'Admin\AdminLoginController@index')->name('admin_login_index');
Route::post('login', 'Admin\AdminLoginController@login')->name('admin_login');

写入两个方法:

public function index()
{
	if ($request->session()->get('admin.user.id')) {
        return redirect()->route('admin_index');
    }

    return view('admin.login');
}

public function login(Request $request)
{
    $input = $request->all();

    $validator = Validator::make($input, [
        'email' => 'required|email|max:128',
        'password' => 'required|min:3',
    ]);

    if ($validator->fails()) {
        return response()->json(['code' => 100, 'msg' => $validator->errors()->first()]);
    }

    // 查询邮箱对应的用户
    $model_user = new User();
    $row_user = $model_user->getUserByEmail($input['email']);

    $msg_error = '账号或密码错误';

    if (!$row_user) {
        return response()->json(['code' => 101, 'msg' => $msg_error]);
    }

    // 校验密码
    if (Hash::check($input['password'], $row_user['password'])) {
        // 密码正确
        $request->session()->push('admin.user.id', $row_user['id']);
        $request->session()->push('admin.user.role', $row_user['role']);
        return redirect()->route('admin_index');
    }

    return response()->json(['code' => 101, 'msg' => $msg_error]);
}

login 方法用了表单验证如果不懂可以看 Laravel 的文档。


中间件

需要创建一个中间件鉴权后台用户登录状态。

php artisan make:middleware CheckAdminLogin

中间件写入:

public function handle($request, Closure $next)
{
    $user_id = $request->session()->get('admin.user.id')[0];

    if (!$user_id) {
        return redirect()->route('admin_login_index');
    }

    return $next($request);
}

注册中间件可以看看官方文档,本文就不写了。

接着写一个路由群组,将后台全部需要登录才能看到的路由都写进这个群组:

Route::middleware(['check_admin_login'])->namespace('Admin')->prefix('admin')->group(function () {
    Route::get('/', 'IndexController@index')->name('admin_index');
});

创建后台页面的控制器:

php artisan make:controller Admin/IndexController

在 IndexController 写入方法:

public function index()
{
    return '后台首页';
}

此时后台登录已经完成。


验证系统管理员权限

由于是系统管理员才能管理角色 / 用户 / 权限 / 以及给用户角色分配权限等等的功能,所以还需要加一个中间件验证是否为系统管理员。

创建中间件:

php artisan make:middleware CheckAdminRole

在中间件写入方法:

public function handle($request, Closure $next)
{
    $role = $request->session()->get('admin.user.role')[0];

    if ($role !== User::ROLE_ADMIN) {
        return redirect()->route('admin_login_index');
    }

    return $next($request);
}


角色管理

角色管理就是个简单的增删查改,本文就不贴角色管理的代码了。

主要就是在中间件路由群组 check_admin_role 中写入路由:

Route::resource('role', RoleController::class);

现在的路由是这样的:

Route::middleware(['check_admin_login'])->namespace('Admin')->prefix('admin')->group(function () {
    Route::get('/', 'IndexController@index')->name('admin_index');

    Route::middleware(['check_admin_role'])->group(function () {
        Route::resource('role', RoleController::class);		// 角色管理增删查改的控制器
    });
});

博主实现的列表:

4.jpg

添加:

5.jpg

样式丑什么的就不要管了~~~


用户管理

和角色管理一样,写一个用户的增删查改即可。

修改路由:

Route::middleware(['check_admin_login'])->namespace('Admin')->prefix('admin')->group(function () {
    Route::get('/', 'IndexController@index')->name('admin_index');

    Route::middleware(['check_admin_role'])->group(function () {
        Route::resource('role', RoleController::class);		// 角色管理增删查改的控制器
        Route::resource('user', UserController::class);		// 用户管理增删查改的控制器	就是加了这个而已
    });
});

实现出来的效果和角色的差不多。


权限管理

和上面两个管理一样,还是增删查改的功能。

写好之后路由继续增加:

Route::resource('auth', AuthController::class);


用户绑定角色

前面已经写好了用户管理的,所以这个是要修改原来的代码。

要实现的功能:给用户选择某些角色绑定后存储数据到 user_roles 表,存储前需要清空一次该用户已存在 user_roles 表的记录,不然会重复。

先要在前面开发好的用户管理和角色管理中添加一些角色和用户。

角色:

6.jpg

用户:

7.jpg

经过修改后的用户列表:

8.jpg

绑定角色的功能:

9.jpg


角色添加权限

和用户绑定角色一样,需要修改之前写的角色管理,选择角色后跳转页面,页面提供选择权限 ( auths 表 ) 并存储,存储到 role_auths 表。

修改完成后的效果:

10.jpg


中间件权限验证

到这一步就是重点了,前面写了这么多无非就是为了中间件可以鉴权。

修改中间件 CheckAdminLogin :

public function handle($request, Closure $next)
{
    $user_id = $request->session()->get('admin.user.id')[0];

    if (!$user_id) {
        return redirect()->route('admin_login_index');
    }

    // 鉴权
    // 先获取该用户对应的全部角色
    $model_user_role = new UserRole();
    $rows_user_role = $model_user_role->selectByUserIds([$user_id]);

    // 根据角色获取全部权限
    $array_role_id = array_column($rows_user_role->toArray(), 'role_id');
    $model_role_auth = new RoleAuth();
    $rows_role_auth = $model_role_auth->selectByRoleIds($array_role_id);
    $array_auth_id = array_column($rows_role_auth->toArray(), 'auth_id');
    $model_auth = new Auth();
    $rows_auth = $model_auth->selectByIds($array_auth_id);

    // 组装全部 URL
    $map_url = [];
    foreach ($rows_auth as $row_auth) {
        $urls = array_column($row_auth['urls']);
        foreach ($urls as $url) {
            $map_url[$url] = $url;
        }
    }

    $uri = $request->route()->uri;
    $role = $request->session()->get('admin.user.role')[0];
    if ($role !== User::ROLE_ADMIN && !isset($map_url[$uri])) {
        exit('无权限访问');
    }

    return $next($request);
}

其实到这一步,发现之前写了两个中间件,第二个中间件 CheckAdminRole 是可以不用的...


测试

弄一个简单的后台首页,IndexContorller 控制器:

public function index()
{
    $html = '<h1>后台首页</h1>';
    $html .= '<div><a href="' . route('role.index') . '">角色管理</a></div>';

    $html .= '<div><a href="' . route('user.index') . '">用户管理</a></div>';

    $html .= '<div><a href="' . route('auth.index') . '">权限管理</a></div>';

    return $html;
}

给测试用户添加一个角色:

11.jpg

使用这个账号登录后台:

12.jpg

给这个角色添加后台首页的权限后刷新:

13.jpg


总结

路由最好不写资源路由,不然后台添加权限 URL 的时候,就不能细分某些权限了。

菜单也是可以完全动态形式控制的,本文仅讲解 RBAC 权限管理的实现方法,代码写得比较烂,可以优化的空间很大。


本文写的代码:https://pan.baidu.com/s/1eWkdnbrlw9v8lP9Luym9lA 

提取码:fvr5

本文地址 : bubaijun.com/page.php?id=205

版权声明 : 未经允许禁止转载!

评论:我要评论
发布评论:
Copyright © 不败君 粤ICP备18102917号-1

不败君

首 页 作 品 微 语