efficiently/authority-controller

Allow closure does not get called when Route Model Binding is enabled

TUNER88 opened this issue · 14 comments

As soon I start using Route Model Binding allow closure does not get called and user get access to the resource. If I disable Route Model Binding everything works fine.

// app/Providers/RouteServiceProvider.php
public function boot(Router $router)
{
    parent::boot($router);

    $router->model('users', 'App\User');
}
if ($user->hasRole('admin')) {
    // works fine 
    // $authority->allow('manage', 'App\User'); 

    // closure does not get called
    $authority->allow('manage', 'App\User', function ($self, $user) {
        return false;
    });

} else {
    $authority->allow('read', 'all');
}

Any ideas how to fix it?
I'm using Laravel 5.

Hi @TUNER88,

I don't use Route Model Binding, but in your code, can you check if
$authority->deny('manage', 'App\User'); works as expected?
Because, I think, but I'm not sure, that the Route Model Binding skip all authorizations rules of the Authority-Controller package.

Cheers,
Tortue Torche

@tortuetorche
$authority->deny('manage', 'App\User'); works as expected.

After hours of debugging, if found that the problem is in $this->loadResource() method.

If i disable Route Model Binding and dump $this->params I get following output:

[▼
  "id" => "1"
  "action" => "show"
  "controller" => "users"
]

$this->loadedInstance()returns true and the resource could be loaded in $this->loadResourceInstance()

If I enable Route Model Bindling, $this->params looks like this:

[▼
  "users" => User {#198 ▶}
  "action" => "show"
  "controller" => "users"
]

$this->loadResource() do nothing if Model Binding is enabled.

The User ResourceInstance is already injected, id is no more available, any idea how to handle this?
Maybe pass something to $this->loadAndAuthorizeResource();?

Thx for your support

Your debugging informations are really useful.
I need to refactor the Parameters class to handle params who contains objects and get the id of these objects. Like I do for string or numeric params.

And I think this issue also occurs with Laravel 4.

@tortuetorche any idea how I can temporary fix in my project, until you update your package?
Its really nice package, i would like continue using it, but disabling Model Binding in whole project is impossible at this moment.

Of course, You can edit the vendor/efficiently/authority-controller/src/Efficiently/AuthorityController/Parameters.php file at line 46 and add the code below:

if (is_a($lastRouteParamKey, '\Eloquent')) {
    $lastRouteParamKey = $lastRouteParamKey->getKey();
}

Warning: Untested code.

Then, You should clear compiled files, with this command:
php artisan clear-compiled

I'll try to fix this issue and add tests in a couple of days.

@tortuetorche thanks for your advice!
Unfortunately I had no success with provided code.

I have forked your repository and patched the code, works fine with one model binding.
If you are interested, you can look at my commit.

Now I can pass model key in the constructor:
$this->loadAndAuthorizeResource(['modelBindingKey' => 'users']);

Am looking forward to new version.

Many thanks @TUNER88, I don't know yet if I'm going to use your code or find another solution but you have done a good job 👍

@tortuetorche thx, this is not the best solution, that's why does not have submitted a merge request.
Multiple model bindings are not supported by current solution, its not so good for nested resources.

You're right

@tortuetorche Any progress?

Hi @TUNER88,

Any progress?

Sorry for the delay. Like I said, I don't use Route Model Binding and I don't think it's a very often used feature, so this issue wasn't a priority for me.
But it should be fixed now 😎

Can you update this package in your application and test again your authorization rules, please?

Cheers,
Tortue Torche

Hi @TUNER88,

I have backported the fix for authority-controller 1.2
If you have still this bug, feel free to reopen this issue.

Cheers,
Tortue Torche