#php #laravel-5.8 #laravel-middleware #policies
Вопрос:
Laravel используется в качестве конечной точки API, я пытаюсь контролировать способность пользователей видеть определенные части сайта в зависимости от того, к какому типу пользователей они относятся. Используя либо $this->authorizeResource()
или $this->authorize()
, он всегда возвращает 403, не затрагивая политики. Комментируя строки, приложение разрешает доступ.
AuthServiceProvider
<?php
namespace ProjectProviders;
use ProjectEntitiesPlumber;
use IlluminateSupportFacadesGate;
use IlluminateFoundationSupportProvidersAuthServiceProvider as ServiceProvider;
use IlluminateSupportFacadesAuth;
use ProjectPoliciesPlumberPolicy;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
Plumber::class => PlumberPolicy::class
];
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
}
}
PlumberPolicy, где все возвращает true ради тестирования.
<?php
namespace ProjectPolicies;
use ProjectEntitiesUser;
use ProjectEntitiesPlumber;
use IlluminateAuthAccessHandlesAuthorization;
class PlumberPolicy
{
use HandlesAuthorization;
/**
* Determine whether the user can view the Plumber.
*
* @param ProjectEntitiesUser $user
* @param ProjectEntitiesPlumber $plumber
* @return mixed
*/
public function view(User $user, Plumber $plumber)
{
//
return true;
}
/**
* Determine whether the user can create Plumbers.
*
* @param ProjectEntitiesUser $user
* @return mixed
*/
public function create(User $user)
{
//
return true;
}
/**
* Determine whether the user can update the Plumber.
*
* @param ProjectEntitiesUser $user
* @param ProjectEntitiesPlumber $plumber
* @return mixed
*/
public function update(User $user, Plumber $plumber)
{
//
return true;
}
/**
* Determine whether the user can delete the Plumber.
*
* @param ProjectEntitiesUser $user
* @param ProjectEntitiesPlumber $plumber
* @return mixed
*/
public function delete(User $user, Plumber $plumber)
{
//
return true;
}
}
Controllers setup.
namespace ProjectHttpControllers;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
}
namespace ProjectHttpControllers;
class ApiController extends Controller
{
public function index(Request $request) { .... }
public function show(Request $request, $id) { .... }
public function store(Request $request) { .... }
public function create(Request $request) { .... }
public function edit(Request $request) { .... }
public function update(Request $request, $id) { .... }
public function destroy(Request $request, $id) { .... }
}
namespace ProjectHttpControllers;
class PlumberController extends ApiController {
public function __construct() {
$this->authorizeResource(ProjectEntitiesPlumber::class);
}
public function show(Request $request, $id) {
return parent::show($request, $id);
}
}
Я перепробовал все предложения по загрузке политики и вызову authorizeResource
и authorize()
со строковыми объявлениями имен классов, чтобы избежать пространств имен и без.
Переходя с помощью Xdebug, кажется, что он терпит неудачу при vendor/laravel/framework/src/Illuminate/Auth/Access/Gate.php
public function authorize($ability, $arguments = [])
{
$result = $this->raw($ability, $arguments);
if ($result instanceof Response) {
return $resu<
}
return $result ? $this->allow() : $this->deny();
}
Where $result = $this->raw($ability, $arguments);
возвращает значение false . $ability = view
и $arguments
= пустой массив.
Я прочитал https://github.com/laravel/framework/issues/22847#issuecomment-521308861 где пользователь упоминает о необходимости передать модель в объявлении метода, чего я не могу сделать с огромной переписью системы.
Список маршрутов
| GET|HEAD | api/plumber | plumber.index | ProjectHttpControllersPlumberController@index | api,auth:api,role:valuer,plumber |
| POST | api/plumber | plumber.store | ProjectHttpControllersPlumberController@store | api,auth:api,role:valuer,plumber,can:create,ProjectEntitiesplumber |
| GET|HEAD | api/plumber/{plumber} | plumber.show | ProjectHttpControllersPlumberController@show | api,auth:api,role:valuer,plumber,can:view,plumber |
| PUT|PATCH | api/plumber/{plumber} | plumber.update | ProjectHttpControllersPlumberController@update | api,auth:api,role:valuer,plumber,can:update,plumber |
| DELETE | api/plumber/{plumber} | plumber.destroy | ProjectHttpControllersPlumberController@destroy
Ответ №1:
Из того, что я обнаружил, это невозможно использовать authorizeResource()
. Вам нужно вызвать $this->authorize()
и передать объект, так как он выдает ошибку с массивом.
class AuthServiceProvider extends ServiceProvider
{
protected $policies = [
Plumber::class => PlumberPolicy::class
];
}
authorize()
ожидает объект, он выдаст ошибку, если передан массив.
class PlumberController extends ApiController
{
public function index(Request $request) {
$this->authorize('viewAny', ProjectEntitiesPlumber::class);
}
public function update(Request $request, $id) {
$plumber = $this->repository->getByID($id);
$this->authorize('update', $plumber);
}
public function store(Request $request) {
$this->authorize('create', ProjectEntitiesPlumber::class);
}
public function show(Request $request, $id) {
$plumber = $this->repository->getByID($id);
$this->authorize('update', $plumber);
}
public function destroy(Request $request, $id) {
$plumber = $this->repository->getByID($id);
$this->authorize('update', $plumber);
}
}