Laravel Policy not working on route middleware - laravel

I have a NotificationPolicy with the following code:
<?php
namespace App\Policies;
use App\Notification;
use App\User;
use Illuminate\Auth\Access\HandlesAuthorization;
class NotificationPolicy
{
use HandlesAuthorization;
public function update(User $user, Notification $notification)
{
return $user->id === $notification->user_id;
}
}
I have registered this properly by adding this to the AuthServiceProvider:
protected $policies = [
Notification::class => NotificationPolicy::class,
];
I have this so that only the logged in user can update their notification by doing things such as setting the archived_at value or read_at value to the current timestamp. The policy does work if I use it in the controller, i.e.;
class ArchiveItemController extends Controller
{
public function __invoke(Notification $notification)
{
$this->authorize('update', $notification);
$notification->markAsArchived();
return redirect()->route('inbox.index')->with('success', 'Item has been archived');
}
}
However I don't want to use them in the controllers and would prefer to use them in my routes file. So I have removed this line $this->authorize('update', $notification); from the controller and I have tried the following but it doesn't work:
Route::prefix('inbox')->middleware(['auth', 'can:employee'])->group(function () {
Route::get('/notification/{notification}/archive', 'User\Account\Inbox\ArchiveItemController')
->name('inbox.item.archive')
->middleware('can:update', 'notification');
});
I've even ran the following but they don't make a difference:
php artisan optimize
php artisan cache:clear
php artisan route:cache
php artisan view:clear
php artisan config:cache

Your middleware declaration is not correct.
You will have to change 'can:update', 'notification' to 'can:update,notification' for it to work:
So in the end you would have the following:
Route::prefix('inbox')->middleware(['auth', 'can:employee'])->group(function () {
Route::get('/notification/{notification}/archive', 'User\Account\Inbox\ArchiveItemController')
->name('inbox.item.archive')
->middleware('can:update,notification');
});
If you have cached the routes, you will have to run php artisan route:clear for the changes to take effect.
From the docs:
Laravel includes a middleware that can authorize actions before the
incoming request even reaches your routes or controllers. By default,
the Illuminate\Auth\Middleware\Authorize middleware is assigned the
can key in your App\Http\Kernel class. Let's explore an example of
using the can middleware to authorize that a user can update a blog
post:
use App\Post;
Route::put('/post/{post}', function (Post $post) {
// The current user may update the post...
})->middleware('can:update,post');
In this example, we're passing the can middleware two arguments. The
first is the name of the action we wish to authorize and the second is
the route parameter we wish to pass to the policy method. In this
case, since we are using implicit model binding, a Post model will be
passed to the policy method. If the user is not authorized to perform
the given action, a HTTP response with a 403 status code will be
generated by the middleware.

Related

Call to undefined method Laravel\Passport\Passport::routes()

I tried to use Laravel-passport so I installed this package in my project, but when i wanted to make route
i wrote this code in the AuthServiceProvider
public function boot()
{
$this->registerPolicies();
Passport::routes();
}
When i run php artisan route:list in the cmd i face with this error
Call to undefined method Laravel\Passport\Passport::routes()
Since version 11 passport's routes have been moved to a dedicated route file. You can remove the Passport::routes() call from your application's service provider.
If you dont want to use default passport routes. you can disabled the route in register method inside AppServicerProvider
public function register()
{
Passport::ignoreRoutes();
}
and you can copy the default passport routes from vendor laravel\passport\routes\web.php
for more detail about UPGRADE read this https://github.com/laravel/passport/blob/11.x/UPGRADE.md
Remove this comment on this line on your AuthServiceProvider file.
protected $policies = [
'App\Models\Model' => 'App\Policies\ModelPolicy',
];

Laravel Authorization can always return false for API

I am trying to use Laravel authorization policies with API and Sanctum. However, I use middleware on the route as follows.
Route::get('/user/orders/{order}',
[OrderController::class, 'get_user_order_detail'])
->middleware('can:view:order');
OrderPolicy.php
namespace App\Policies;
use App\Models\Order;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
class OrderPolicy
{
use HandlesAuthorization;
/**
* Create a new policy instance.
*
* #return void
*/
public function __construct()
{
// dd(1);
}
public function view(User $user, Order $order): bool
{
return $user->id === $order->user_id;
}
}
As you see, when I add dd(1) inside the constructor of the OrderPolicy, then I get 1 as expected, but when I move it to the inside of view function, I get unauthorized which indicates that is maybe the view function itself is not being called, but, the OrderPolicy is getting called.
Your middleware definition is wrong:
->middleware('can:view:order')
it should be:
->middleware('can:view,order')
From the docs:
Laravel includes a middleware that can authorize actions before the incoming request even reaches your routes or controllers. By default, the Illuminate\Auth\Middleware\Authorize middleware is assigned the can key in your App\Http\Kernel class. Let's explore an example of using the can middleware to authorize that a user can update a post:
use App\Models\Post;
Route::put('/post/{post}', function (Post $post) {
// The current user may update the post...
})->middleware('can:update,post');
In this example, we're passing the can middleware two arguments. The
first is the name of the action we wish to authorize and the second is
the route parameter we wish to pass to the policy method. In this
case, since we are using implicit model binding, a App\Models\Post
model will be passed to the policy method. If the user is not
authorized to perform the given action, an HTTP response with a 403
status code will be returned by the middleware.

send get request to specific file

I have a file called: test.php located in public/inc/test.php. Through jQuery, I can make a get request through jQuery ($.get), by typing:URL: "public/inc/test.php?" + param1` etc.
I want to do the same, but through Laravel. I want to have a route called: /sendparams/{param1}/{param2}, and do a get request to the test.php file from inside a route in web.php and pass the params variables.
How should the route be written?
edit:
by implementing the classes in laravel as external classes, this is no more needed.
you have in your laravel project a file named web.php inside the routes folder.
Define within the web.php file the below code:
Route::get('/sendparams/{param1}/{param2}', 'ControllerName#index');
Perform the below command to create the controller
php artisan make:controller ControllerName
Open ControllerName (app/Http/Controllers/ControllerName)
Your new controller has an structure like this:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class MailController extends Controller
{
public function __construct()
{
}
/* This is the method executed in your route defined in web.php*/
public function index(Request $request) {
$param1 = $request->param1;
$param2 = $request->param2;
$allParams = $request->all(); // returns an associative array with all params
}
}
you can check your routes performed the below command
php artisan route:list
Regards

How to alter all Request in laravel

I'm receiving requests from new front end which encrypt all of the post parameters
the previous frontend didn't encrypt the post parameters
however the current backend also doesn't decrypt the post parameters received
how do i alter the whole request received so that i can put the decryption first when calling the
$request->get('param_name');
so that when the value of param_name gets into the variables to be used, it's already decrypted
because modifying the whole backend 1 by 1 is really inefficient
i've ever alter the trans() function, just go the file that handles it and alter it
but on request
what is the file?
You can use middleware.
php artisan make:middleware RequestInterceptorMiddleware
Then in the handle method you can interrogate the request and perform a .merge()
if($request->has('param_name')) {
$request->merge(['param_name' => decrypt($request->get('param_name'))]);
}
return $next($request);
And then make sure to add that middleware to your Kernel.php in your corresponding route middleware declarations.
You need create middleware for you action.
php artisan make:middleware RequestDecryptMiddleware
In Kernel.php add:
<?php
// Kernel.php
protected $routeMiddleware = [
...
'decrypt' => \App\Http\Middleware\RequestDecryptMiddleware::class,
...
];
After it you can overide params in middleware:
public function handle($request, Closure $next)
{
if($request->has('encrypt_param')){
$request->merge(['encrypt_param' => decrypt_function($request->get('encrypt_param'))]);
}
return $next($request);
}
Then use it in you controller:
public function myAction(RequestDecryptMiddleware $request)...

Hot to use custom Request class instead NovaRequest (FormRequest) for creating resuorce in Laravel Nova?

I make:
php artisan make:request DiscoverRequest
I want use DiscoverRequest instead default NovaRequest for create new entity for specific resource.
In Laravel Nova exist unified ResourceStoreController for all resources.
public function handle(CreateResourceRequest $request)
Route::post('/{resource}', 'ResourceStoreController#handle');
I want to override Request only for one resource.
How this can be implemented?
Can you elaborate what you mean by "override Request for only one resource"?
Normally you can just type hint the new Request in the method like this:
<?php
namespace App\Http\Controllers;
use App\Http\Requests\StoreItineraryRequest;
class ResourceStoreController extends Controller
{
public function handle(DiscoverRequest $request) {
...
}
}

Resources