Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?

Anyone new to RBAC I highly suggest using laravel's or Spatie https://github.com/spatie/laravel-permission

However being familiar with RBAC I use built in authentication but have custom authorization.

I use static helper classes, but instance will also work. And these are just simple examples of making sure a required role of a method matches with one of the logged in users role.

I have a role field in users table like:

   role 
  -------------
  admin
  bkeep     // for bookkeeper
  admin,bkeep   // both roles
  user

Make whatever helper or service class you desire.

In a helper class I have:

    public static function chkRole($role = null)
    {
        $userrole = Auth::user()->role;
        $checkrole = explode(',', $userrole);
        if (in_array($role, $checkrole)) {
            return true;
        }
        return false;
    }

Usage at method level:

    public function indexAdmin()
    {
        if (!ChkAuth::chkRole('admin')) {
            return redirect('indexbl'); // whereever you redirect
        }
        // rest of method if role matches.

Situation where user can see and edit their own data only:

Example in an edit method

       $petid = $request->input('petid');
        $pet = Pet::find($petid);
        ChkAuth::chkUserId($pet->owner_id);
        // owner_id  is FK

And helper method that verifies this:

    public static function chkUserId($userid)
    {
        if ($userid === Auth::user()->id || self::chkRole('admin') === true) {
            return;
        } else {
            die(redirect('/login')); // where ever you redirect to
          }
        return false;
    }

Note above die should never be called unless a user tries to enter another id in the url which can happen.

Notice this line:

if ($userid === Auth::user()->id || self::chkRole('admin') === true) {

It's for a situation where user can handle their own data, but an admin can see and edit all. For that a scope is handy:

Scope example:

    public function scopegetPets($query, $petsearch = '')
    {
        $petsearch = $petsearch . "%";
        $query->where('petname', 'like', $petsearch);
        if (ChkAuth::chkRole('admin') === false) {
            $userid = Auth::user()->id;
            $query->where('ownerid', '=', $userid);
        }
        $results = $query->orderBy('petname', 'asc')->paginate(5);
        return $results;
    }

Notice this part

        if (ChkAuth::chkRole('admin') === false) {
            $userid = Auth::user()->id;
            $query->where('ownerid', '=', $userid); //whatever fk used
        }

Is used if a regular user, but not part of query if admin, since admin can see or edit all.

These are just a few ways to use out of box authentication with some custom authorization.

This is not a class to use, just examples. If you use custom RBAC add more custom methods as needed in your custom class.

@jimgwhit

This comment has been minimized.

Copy link
Owner Author

jimgwhit commented Jan 31, 2020

Also a true false can be used to verify the correct user is viewing or editing:

    public static function chkUserId($userid)
    {
        if ($userid === Auth::user()->id || self::chkRole('admin') === true) {
            return true;
        }
        return false;
    }

Or if checking user only, leave out the admin part:

    public static function chkUserId($userid)
    {
        if ($userid === Auth::user()->id) {
            return true;
        }
        return false;
    }

Called via:

    public function edit(Request $request)
    {
        $petid = $request->input('petid');
        $pet = Pet::find($petid);
        if(ChkAuth::chkUserId($pet->owner_id) == false){
            return redirect('someplace');
        }
        return view('pet/edit', compact('pet'));
    }

Of course a combination of custom authorization and middleware can be used. Again just examples here.

@jimgwhit

This comment has been minimized.

Copy link
Owner Author

jimgwhit commented Feb 28, 2020

So in summary, the flow goes something like:

  • Bob is an admin

  • Suzy is admin and does bookkeeping

  • Mary is a bookkeeper only

  • If Bob is logged in, Bob can only do admin stuff and all access to user stuff. But Bob cannot mess with bookkeeping.

  • If Suzy is logged in she can access admin stuff and bookkeeping and accounting stuff.

  • If Mary is logged in she cannot mess with admin stuff, but has access to bookkeeping and accounting stuff.

So I just check at method level if the logged in users role can or cannot access that method / function.

And use query scopes to let a user edit / view their own data or an admin can access all users data.

Each app will be different as to who can do what. I have nothing against any built in ACL, but I just like my custom RBAC (role based access control) better.

So in pseudocode:

public function makeInvoice()
    {
        if (a required role of bkeep is not true here) {   // bkeep = bookkeeper
            return redirect('somewhere'); // whereever you redirect to if not authorized
        }
        // Rest of method here is accomplished if 
        // the logged in used has the required role of 'bkeep'.
    }

Again just examples.

Also a Spatie example I saw:

public function update(Request $request, Post $post) {
    if ($post->author !== auth()->user()->id || auth()->user()->cannot('edit posts'))
        abort(404);// or redirect, or whatever action 
    }
    //rest of method if all okay
}

In summary RBAC is at least 3 main steps:

  • A login required
  • An authorization implementation to determine what the logged in person with role can or cannot do
  • Protection of URL and parameters, checking that the logged in users id matches the id used in a query

Each application will require unique tweaks in RBAC, no two apps are exactly the same.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.