Reputation: 1999
In my Laravel application, administrators can be assigned to jobs, I also have super administrators that can do everything.
Administrators that are not super administrators should only be able to access jobs they are assigned to.
Let's use a rough route for illustration:
http://localhost:3000/jobs/{job}
http://localhost:3000/jobs/{job}/notes{note}
In this scenario {job}
is an id acquired via route model binding and a note is attached to a job.
Administrators assigned to jobs are done so via the following relationship method:
/**
* Get the jobs that this admin has access to via the pivot table
*
* @return void
*/
public function jobs()
{
return $this->belongsToMany(JobPost::class, 'job_post_admin', 'admin_id', 'job_post_id');
}
So I can use $user->jobs
I want to be able to say the following - if you're a super admin you can go anywhere, if you're not, you should be restricted to what you've been assigned to.
So if a user only has access to http://localhost:3000/jobs/{1}
and they go to http://localhost:3000/jobs/{2}
they should be redirected.
I created a Middleware called Access
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if (Auth::guard('admin')->user()) {
$user = Auth::guard('admin')->user();
if ($user->is_admin) {
return $next($request);
} else {
if ($user->jobs->contains($job)) {
return $next($request);
} else {
return response('You do not have sufficient priveledges to perform this action.', 403);
}
}
} else {
return redirect()->back();
}
}
However, I'm confused as to how I would get the job ID from the URL.
I have a working MiddleWare that looks like this:
<?php
namespace App\Http\Middleware;
use Closure;
use Auth;
class Access
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if (Auth::guard('admin')->user()) {
$user = Auth::guard('admin')->user();
$job = $request->vacancy;
if ($user->is_admin) {
return $next($request);
} else {
if ($user->jobs->contains($job)) {
return $next($request);
} else {
return response('You do not have sufficient priveledges to perform this action.', 403);
}
}
} else {
return redirect()->back();
}
}
}
I am now interested though, as without sounding dense I haven't really acknowledged authorization in Laravel, does it have benefits over Middleware?
Upvotes: 0
Views: 497
Reputation: 40690
Authentication is different to authorization. Laravel supports both.
You can do what you need using authorisation policies, there is no need for extra middleware.
First create a policy:
php artisan make:policy JobsPolicy --model=Job
This will make your boilerplate. Then you can add the actions:
class JobsPolicy {
use HandlesAuthorization;
//If you return true here the policy always succeeds
public function before(User $user, $ability) {
if ($user->is_admin) {
return true;
}
}
public function view(User $user, Job $job) {
return $user->jobs->contains($job);
}
public function create(User $user) {
return true; //Return true if the user can create jobs
}
public function update(User $user, Job $job) {
return $user->jobs->contains($job);
}
}
You need to also register your policy in the AuthServiceProvider
in the $policies
array:
protected $policies = [
Job::class => JobPolicy::class
];
Then you can add the already existing middleware e.g.:
Routes::get('jobs/{job}/notes/{note}', ...)->middleware("can:view,job");
This will ensure that the currently authenticated user can
view
the job
specified by the route job parameter.
There's more information in the documentation
Upvotes: 2