使用与另一个模型的策略的关系

Use relationship with policy of another model

我正在使用 Laravel v5.5.14.

我有一个端点,App\Message in routes/api.php:

Route::group(['middleware' => 'auth:api'], function() {

    Route::put('messages/{message}', 'MessageController@update')->middleware('can:view,pet');

});

我想在这里应用我的 PetPolicy.php 中定义的 can:view,pet 策略:

namespace App\Policies;

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

class PetPolicy
{
    use HandlesAuthorization;

    public function view(User $user, Pet $pet)
    {
        return $user->pets()->where('pet_id', $pet->id)->exists();
    }
}

每个 App\Message 都有一个 App\Pet 我声明宠物在我的模型中有很多消息(一对多)关系。每个 App\User 可以有很多 App\Pet 如此多对多。

app/Pet.php:

namespace App;

use Illuminate\Database\Eloquent\Model;

class Pet extends Model
{
    protected $fillable = ['name'];

    public function messages()
    {
        // one-to-many hasMany belongsTo
        return $this->hasMany('App\Message');
    }

    public function users()
    {
        // many-to-many belongsToMany "
        return $this->belongsToMany('App\User');
    }
}

app/Message.php:

namespace App;

use Illuminate\Database\Eloquent\Model;

class Message extends Model
{
    protected $fillable = ['body', 'kind'];

    public function pet()
    {
        // one-to-many hasMany belongsTo
        return $this->belongsTo('App\Pet');
    }
}

app/User.php:

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable;

    // ....

    public function pets()
    {
        // many-to-many belongsToMany "
        return $this->belongsToMany('App\Pet');
    }    

    public function messages()
    {
        // one-to-many hasMany belongsTo
        return $this->hasMany('App\Message');
    }
}

但是我的政策失败了,它总是在未经授权的情况下给予。我是不是哪里弄错了?

这是我的 app/AuthServiceProvider.php:

namespace App\Providers;

use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    protected $policies = [
        'App\Pet' => 'App\Policies\PetPolicy',
        'App\Message' => 'App\Policies\MessagePolicy'
    ];

    public function boot()
    {
        $this->registerPolicies();
    }
}

谢谢

用这个查询测试它:

namespace App\Policies;

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

class PetPolicy
{
    use HandlesAuthorization;

    public function view(User $user, Pet $pet)
    {
        return User::where('id', $user->id)
                    ->whereHas('pets', function ($query) use($pet) {
                            $query->where('id', $pet->id);
                        })
                    ->exists();
    }
}

如果你愿意,也可以像这样:

return $user->pets->contains($pet->id);

或者像这样:

return DB::table('pet_user')
    ->whereUserId($user->id)
    ->wherePetId($pet->id)
    ->count() > 0;