【原创】Laravel中的权限系统

中间件

Laravel 内置了一些中间件,例如身份验证、CSRF 保护等。所有的中间件都存放在 app/Http/Middleware 文件夹中。

<?php

namespace App\Http\Controllers;

class UsersController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth', [            
            'except' => ['show', 'create', 'store']
        ]);
    }
}

middleware 方法接收两个参数,第一个是中间件的名称,第二个是要进行过滤的动作。
except 方法用来设定指定动作不使用 Auth 中间件进行过滤,即除了此处指定的动作以外,所有其他动作都必须登录用户才能访问,类似于黑名单的过滤机制。
only 方法只过滤指定动作。

在控制器 Auth 中间件使用中,首选 except 方法,这样的话,当新增一个控制器方法时,默认是安全的,此为最佳实践。

授权策略

创建授权策略

php artisan make:policy UserPolicy

所有生成的授权策略文件都会被放置在 app/Policies 文件夹下。
app/Policies/UserPolicy.php

<?php

namespace App\Policies;

use Illuminate\Auth\Access\HandlesAuthorization;
use App\Models\User;

class UserPolicy
{
    use HandlesAuthorization;

    public function update(User $currentUser, User $user)
    {
        return $currentUser->id === $user->id;
    }
}

注册授权策略

Laravel 提供两种注册授权策略的方式,第一种是手动指定,第二种是自动授权注册。自动授权注册如下:

app/Providers/AuthServiceProvider.php

<?php

namespace App\Providers;

class AuthServiceProvider extends ServiceProvider
{
    .
    .
    .
    public function boot()
    {
        $this->registerPolicies();
        // 修改策略自动发现的逻辑
        Gate::guessPolicyNamesUsing(function ($modelClass) {
            // 动态返回模型对应的策略名称,如:// 'App\Models\User' => 'App\Policies\UserPolicy',
            return 'App\Policies\\'.class_basename($modelClass).'Policy';
        });
    }
}

授权策略定义完成之后,便可以在控制器中使用 authorize 方法来验证用户授权策略。默认的 App\Http\Controllers\Controller 类包含了 Laravel 的 AuthorizesRequests trait。此 trait 提供了 authorize 方法,它可以被用于快速授权一个指定的行为,当无权限运行该行为时会抛出 HttpException。authorize 方法接收两个参数,第一个为授权策略的名称,第二个为进行授权验证的数据。

引用:

<?php

namespace App\Http\Controllers;

class UsersController extends Controller
{

    public function edit(User $user)
    {
        $this->authorize('update', $user);
        return view('users.edit', compact('user'));
    }

    public function update(User $user, Request $request)
    {
        $this->authorize('update', $user);
        $this->validate($request, [
            'name' => 'required|max:50',
            'password' => 'nullable|confirmed|min:6'
        ]);

        $data = [];
        $data['name'] = $request->name;
        if ($request->password) {
            $data['password'] = bcrypt($request->password);
        }
        $user->update($data);

        session()->flash('success', '个人资料更新成功!');

        return redirect()->route('users.show', $user);
    }
}

友好的重定向

重定向到用户登录之前访问的页面:

<?php

namespace App\Http\Controllers;

class SessionsController extends Controller
{
    public function store(Request $request)
    {
       $credentials = $this->validate($request, [
           'email' => 'required|email|max:255',
           'password' => 'required'
       ]);

       if (Auth::attempt($credentials, $request->has('remember'))) {
           session()->flash('success', '欢迎回来!');
           $fallback = route('users.show', Auth::user());
           return redirect()->intended($fallback);
       } else {
           session()->flash('danger', '很抱歉,您的邮箱和密码不匹配');
           return redirect()->back()->withInput();
       }
    }
    .
    .
    .
}

redirect()intended 方法可将页面重定向到上一次请求尝试访问的页面上,并接收一个默认跳转地址参数,当上一次请求记录为空时,跳转到默认地址上。

注册与登录页面访问限制

只让未登录用户访问登录页面:

<?php

namespace App\Http\Controllers;

class SessionsController extends Controller
{
    public function __construct()
    {
        $this->middleware('guest', [
            'only' => ['create']
        ]);
    }
}

只让未登录用户访问注册页面:

<?php

namespace App\Http\Controllers;
class UsersController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth', [
            'except' => ['show', 'create', 'store']
        ]);

        $this->middleware('guest', [
            'only' => ['create']
        ]);
    }
}    

app/Http/Middleware/RedirectIfAuthenticated.php

<?php

class RedirectIfAuthenticated
{

    public function handle(Request $request, Closure $next, ...$guards)
    {
        $guards = empty($guards) ? [null] : $guards;

        foreach ($guards as $guard) {
            if (Auth::guard($guard)->check()) {
                session()->flash('info', '您已登录,无需再次操作。');
                return redirect(RouteServiceProvider::HOME);
            }
        }

        return $next($request);
    }

    }
}

app/Providers/RouteServiceProvider.php

class RouteServiceProvider extends ServiceProvider
{
    /**
     * The path to the "home" route for your application.
     *
     * This is used by Laravel authentication to redirect users after login.
     *
     * @var string
     */
    public const HOME = '/';
点赞

发表回复

电子邮件地址不会被公开。必填项已用 * 标注