Reputation: 439
I'm using the laravel-backpack admin for the administration section of my app, as well as I'm using the PermissionManager
for managing user roles and permissions. Now I want to assign specific access to specific data.
for example, imagine we have an article management system, as well as we have an editor
role and its related permission for a user whose username is user24
, so the desired way is that the user24
must access to specific articles like article 1
in their dashboard or crud list.
Articles
table's structure:
NOTE: the 'user_id' field refers to the owner of the article.
|---------------------|------------------|------------------|
| id | title | user_id |
|---------------------|------------------|------------------|
| 1 | article1 | 2 |
|---------------------|------------------|------------------|
Upvotes: 1
Views: 1136
Reputation: 19571
One way to accomplish this it to create a second class called CrudArticle
(or whatever), make it extend the original Article class but then, add a global scope to this model that limits all queries to the table using the class to only include records that belong to the current user. Use this class with your CRUD panel and the normal Articles class elsewhere in your application.
class CrudArticle extends Article {
public static function boot()
{
parent::boot();
// only include models that belong to this user
$user_id = 0;
Auth::check();
if ($user = Auth::user()) {
$user_id = $user->id;
}
static::addGlobalScope('userFilter', static function (Builder $builder) use ($user_id){
$builder->where('user_id', $user_id);
});
}
}
Another way to accomplish this is to modify the queries used by the CRUD for example, in your CRUD controller:
/**
* Set up the "list" or "read" operation for the resource
*/
public function setupListOperation(): void
{
// ... normal setup code ...
Auth::check();
$user = Auth::user();
if (!$user) {
throw new \Exception('Unauthorized');
}
$this->crud->query = $this->crud->query->where('user_id', $user->id);
}
To prevent viewing of the update page via a direct url, you can add something like this to setupUpdateOperation:
/**
* Set up the "update" operation for the resource
*/
public function setupUpdateOperation(): void
{
// ... normal setup code ...
$authorized = false;
// only allow viewing the update page if the user is logged in and owns the Article
Auth::check();
if ($user = Auth::user()) {
$id = $this->get('id');
$product = Article::find($id);
if ($product) {
$authorized = $product->user_id === $user->id;
}
}
if (!$authorized) {
$this->crud->denyAccess(['update']);
}
}
To prevent unauthorized edits posted directly to the update endpoint, you'll need to also add something like the below to your UpdateRequest:
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
$authorized = false;
// only allow updates if the user is logged in and owns the Article
Auth::check();
if ($user = Auth::user()) {
$id = $this->get('id');
$product = Article::find($id);
if ($product) {
$authorized = $product->user_id === $user->id;
}
}
return $authorized;
}
Alternatively, you could add a global scope to the model in question as explained here though I tend to avoid that as it changes behavior across the whole app
Upvotes: 1