Laravel策略 - 错误或实施错误?

时间:2017-11-16 11:57:14

标签: php laravel authorization

我在Laravel中实现了如下用户策略。

namespace App\Policies;

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

class UserPolicy
{
    use HandlesAuthorization;

    /**
     * Determine whether the user can list the model.
     *
     * @param  \App\User  $user
     * @return mixed
     */
    public function index(User $user)
    {
        // only a chief editor can view all users
        $authorized = false;
        $authorized = ($user->role->name === 'Chief Editor');
        return $authorized;
    }

    /**
     * Determine whether the user can view the model.
     *
     * @param  \App\User  $user
     * @param  \App\User  $model
     * @return mixed
     */
    public function view(User $user, User $model)
    {
        // only a chief editor or user(who owns the user) can view the user
        $authorized = false;
        $authorized = ($user->role->name === 'Chief Editor' || $user->id === $model->id);
        return $authorized;
    }

    /**
     * Determine whether the user can create models.
     *
     * @param  \App\User  $user
     * @return mixed
     */
    public function create(User $user)
    {
        // only a chief editor can create a user
        $authorized = false;
        $authorized = ($user->role->name === 'Chief Editor');
        return $authorized;
    }

    /**
     * Determine whether the user can update the model.
     *
     * @param  \App\User  $user
     * @param  \App\User  $model
     * @return mixed
     */
    public function update(User $user, User $model)
    {
        // only a chief editor or user(who owns the user) can update the user
        $authorized = false;
        $authorized = ($user->role->name === 'Chief Editor' || $user->id === $model->id);
        return $authorized;
    }

    /**
     * Determine whether the user can delete the model.
     *
     * @param  \App\User  $user
     * @param  \App\User  $model
     * @return mixed
     */
    public function delete(User $user, User $model)
    {
        // only a chief editor or user(who owns the user) can delete the user
        $authorized = false;
        $authorized = ($user->role->name === 'Chief Editor' || $user->id === $model->id);
        return $authorized;
    }
}

这是我的用户控制器。

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Requests\StoreUser;
use App\Http\Requests\UpdateUser;

use App\User;
use App\Role;

class UserController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');
        $this->middleware('can:index,App\User')->only('index');
        $this->middleware('can:view,user')->only('show');
        $this->middleware('can:create,App\User')->only('create', 'store');
        $this->middleware('can:update,user')->only('edit', 'update');
        $this->middleware('can:delete,user')->only('destroy');
    }
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $users = User::paginate(5);
        return view('users.index')
                ->with('users', $users);
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        // fetch roles
        $roles = Role::all();
        return view('users.create')
                ->with('roles', $roles);
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(StoreUser $request)
    {
        //
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        $user = User::findOrFail($id);
        return view('users.show')
                ->with('user', $user);
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        $user = User::findOrFail($id);
        return view('users.edit')
                ->with('user', $user);
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(UpdateUser $request, $id)
    {
        //
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        //
    }
}

但是,当我在策略方法中访问具有多个参数的操作(两个用户对象)时,我收到This action is unauthorized.错误。

我还尝试在不使用这些方法的任何检查的情况下返回true但仍然存在同样的问题。

这是我的代码问题还是Laravel的错误?

1 个答案:

答案 0 :(得分:0)

更新:您的代码无效,因为您没有将第二个用户传递给该政策。

您没有使用路由模型绑定,因此传递给view方法的用户不存在。当模型不存在时,Laravel将不会检查策略并返回false。

以下是文档中的示例,它的工作原理是路由模型绑定。

Route::put('/post/{post}', function (Post $post) {
    // The current user may update the post...
})->middleware('can:update,post');

答案:

在控制器构造函数中使用授权是没有意义的。如果要使用中间件进行授权,请将其附加到不是控制器的路径上。

如果您允许请求到达控制器,那么最好检查操作中的授权而不是构造函数。它也更容易阅读和调试。

我会从构造函数中删除对can中间件的所有调用,并将其替换为操作中对authorize的调用。

你的控制器应该是这样的:

public function __construct()
{
    $this->middleware('auth');
}

public function index()
{
    $this-authorize('index'); // This will check for authorization

    $users = User::paginate(5);
    return view('users.index')
            ->with('users', $users);
}


public function show($id)
{
    $user = User::findOrFail($id);

    $this->authorize('view', $user);

    return view('users.show')
            ->with('user', $user);
}

此外,您的策略类中不需要temprory变量。

public function index(User $user)
{
    // only a chief editor can view all users

    return $user->role->name === 'Chief Editor'
}

public function view(User $user, User $model)
{
    // only a chief editor or user(who owns the user) can view the user

    return $user->role->name === 'Chief Editor' || $user->id === $model->id)
}

作为旁注,在您的节目动作中,为什么不使用implicit route model binding?它会更清洁。

// web.php

Route::get('users/{user}', 'UserController@show');


// UserController.php

public function show(User $user)
{
    $this->authorize('view', $user);

    return view('users.show', compact('user');
}