3分钟短文:任命管理员,给Laravel普通用户提权

引言

系统内使用User表记录用户的属性,各自维护用户自身的关联数据。

有一些前端页面也会需要分别根据身份展示不同级别的内容。

img

本期为大家说一说给普通用户提权为 管理员。

数据准备

我们希望在users表内指定用户的身份,比如任命为管理员,则可以展示更多的数据资源。

我们在users表内追加一个字段 is_admin 用于标记用户的管理员身份,使用命令创建迁移文件:

php artisan make:migration add_is_admin_to_user_table --table=users

首先填充 up 方法用于迁移执行的逻辑:

public function up()
{
    Schema::table('users', function(Blueprint $table)
    {
        $table->boolean('is_admin')->default(false);
    });
}

如果迁移失败,进行回滚使用的 down 方法:

public function down() 
{
    Schema::table('users', function(Blueprint $table)
    {
        $table->dropColumn('is_admin');
    }
}

完成编辑后保存,并执行迁移指令:

php artisan migrate

为了测试,我们使用mysql客户端直接连接数据库,并手动指定一个管理员,使用下面的SQL语句:

update users set is_admin = true where email = 'admin@admin.com';

路由

为了区别于普通用户的前端页面,我们使用新的命名空间 Admin 放置管理员相关的代码。首先创建控制器:

php artisan make:controller Admin/UsersController

然后添加路由,编辑 routes/web.php 文件并添加以下内容:

Route::group(['prefix' => 'admin', 'namespace' => 'Admin'], function()
{
    Route::resource('user', 'UsersController');
});

注意我们使用了两个关键的参数,

  • prefix : 也就是该组内的所有路由地址,使用 prefix 最为前缀
  • namespace : 命名空间,指定该组内所有的控制器,均位于该命名空间下。

控制器

上一节的路由我们定义的是资源路由,使用restful风格声明。下面创建 app/Http/Controllers/admin/UsersController.php 文件,并实现 index 方法。代码内容如下:

public function index()
{
    $users = User::orderBy('created_at', 'desc')->get();
    return view('admin.users.index')->withUsers($users);
}

我们还需要一个视图文件,承载上述的数据。创建目录 resources/views/admin/users/index.blade.php,简单创建一个模板:

<h1>Registered Users</h1>
<ul>
    @forelse ($users as $user)
        <li>{{ $user->name }} ({{ $user->email }})</li>
    @empty
        <li>No registered users</li>
    @endforelse
</ul>

展示的是所有用户的信息。这显然必须拥有较高的权限。所以我们在给数据之前,要识别用户是否管理员:

if (Auth::user()->is_admin != true) {
    return redirect()->route('home')->withMessage('Access denied!');
}

如果不是就路由到首页。这样的判断,如果页面多了起来之后,每次都要在控制器内敲写,着实麻烦。所以,必须使用更靠前的验证,也就是 中间件

中间件

中间件可以注册给路由文件,在命中路由后,调用中间件进行身份识别,这是不错的选择。

使用命令行创建中间件文件:

php artisan make:middleware AdminAuthentication

生成的文件位于 app/Http/Middleware/ 目录下,编辑 AdminAuthentication 文件,并实现代码逻辑:

namespace App\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Http\RedirectResponse;

class AdminAuthentication {
    public function handle($request, Closure $next)
    {
        if ($request->user())
        {
            if ($request->user()->is_admin == true)

            {
                return $next($request);
            }
        }

        // 验证不通过
        return new RedirectResponse(url('/'));
    }
}

然后在 app/Http/Kernel.php 文件内注册该中间件,并命名:

protected $routeMiddleware = [
    'admin' => \App\Http\Middleware\AdminAuthentication::class,
];

修改 路由 一节中声明的路由组,引入中间件:

Route::group(
[
    'prefix' => 'admin',
    'namespace' => 'admin',
    'middleware' => 'admin'
], function()
{
    Route::resource('users', 'UsersController');
});

写在最后

本文又是一个功能齐全却又mini小巧的短文,详细阐述了如何为users表添加管理员功能。

通过注册路由到中间件的使用,又一次体验了laravel各个组件协同作用的能力!

Happy coding :-)

我是@程序员小助手,专注编程知识,圈子动态的IT领域原创作者

本作品采用《CC 协议》,转载必须注明作者和本文链接
write-less-do-more-make-you-out-of-door
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
讨论数量: 5

那中间件是放在控制器里还是路由比较好点?

2天前 评论

 public function handle($request, Closure $next)
 {
        if ($request->user()->is_admin ?? false)
        {
            return $next($request);
        }

        // 验证不通过
        return new RedirectResponse(url('/'));
  }

大师,这样是不是更简洁一点

1天前 评论

@浪里小白龙 最后一节可以看到,中间件是注册给 路由 使用的。

如果有特殊的对于某个控制器内 特殊专用 的中间件,那么可以在 __construct() 方法内引入。

1天前 评论

@L学习不停 链式写可能抛出异常。

$request->user() 返回一个 User 模型对象; 如果不存在,或者非登录状态,返回 null; 对于 null 对象,调用 is_admin 属性,抛出 属性不存在 的异常。

所以第一步,需要确定 $request->user() 返回了对象实例,然后才能读取 is_admin 的值。这也就是说明了,为什么用两层 if 判断。

1天前 评论
L学习不停 1天前
liutao_me 1天前
程序员小助手 (作者) (楼主) 1天前

讲道理.. 一行 Gates 就解决的功能...

Gates

1天前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!