Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

trevorpan's avatar

Implementing a user interface for Roles & Permissions

https://laracasts.com/series/whats-new-in-laravel-5-1/episodes/16

I've got a decent handle on creating the tables, etc. However, how have you solved this issue?

The goal on the dashboard is for an admin to be able to add a user to a role/permission. e.g. on this site a company owner may want to have 3 employees be able to bid on jobs. I want the owner to have control; if a user is fired or leaves the company the owner/admin can delete their roles/permission on that company without the website admin from having to do all this tedious work.

If a user is a member of the site does the admin type an email and then this is saved to the roles/permissions table? Then do you display these company users to the company admin? Like a looped list.

The dashboard currently has an invitation form which allows an existing user to invite others (there's a method which checks if an email already exists); it seems like this should stay vanilla and then only someone who is a user can be added for Roles & Permissions.

Trying to wrap my head around this problem.

0 likes
13 replies
trevorpan's avatar

sorry I missed your post, @jlrdw

Mainly, I'm interested in the user interface. e.g. what's it look like to add a role, permission?

jlrdw's avatar

In laravel I believe most use a roles table, but punch this into google, quite a few past answers:

site:laracasts.com roles and permissions

But if admin is adding them, just a form and relations to the tables like any other related data.

I prefer a comma separated list like in my example, but as long as everything is secure is the goal.

trevorpan's avatar

Ok, so a form like:

//form code
<div class="form-group">
            
// backend code checks for email
    <input type="email" placeholder="email"> 

    <label for="companyrole">Company Role</label>
    <select class="form-control" id="companyrole">
        <option value="CEO">CEO</option>
        <option value="Employee">Employee</option>
    </select>

    <label for="companypermissions">Company Permissions</label>
    <select class="form-control" id="companypermissions">
        <option value="Can view all financials">Can view all financials</option>
        <option value="Can bid">Can bid</option>
    </select>

    <button id="submit" type="submit">Add role/permissions</button>-
</div>

In this case above, the check on email...it seems like the person should have to accept if their email isn't from the same domain?

trevorpan's avatar

still having an issue with this implementation.

From what I gather on all ACL, Roles & Permissions videos on laracasts you want to have the roles/permissions defined in the roles and permissions tables. Using tinker this is quite easy to attach roles/permissions - like the videos.

Using a dashboard and an input box and html selects gives an error:

    The email field is required.
    The companyrole field is required.
    The companypermissions field is required.

It feels like after validation the controller wants to create an object - and gives the error. How would you make it possible to attach the roles without throwing this error?

Here's the controller:

/**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $this->validate(request(), [
            'email' => 'required|string|email|max:255',
            'companyrole' => 'required|string|min:3',
            'companypermissions' => 'required|string|min:3',
        ]);

        $roleExists = Role::roleExists(request('companyrole'));
        $permissionExists = Permission::permissionExists(request('companypermissions'));

        if ($roleExists === true && $permissionExists === true) {

//            $userEmailExists = User::userEmailExists(request('email'));
            $user = User::userExists(request('email'));

            if ($user) {

                $companyHasAdministrator = Role::CompanyHasCompanyAdministrator(request('companyrole'));

                if ($companyHasAdministrator === false) {

                    $role = request('companyrole');
                    $permission = request('companypermissions');

                    $user->roles()->attach($role);
                    $user->permissions()->attach($permission);

                    flash('Thank you for adding roles and permissions.')->success();

                    return back();

                } else {

                    flash('This company already has an administrator.')->warning();

                    return back();
                }

            } else {

                flash('No one with that email exists. Would you please invite them in the Invitations Center below? After they accept you may add their roles and permissions.')->warning();

                return back();

            }


        } else {

            flash('You have been reported to the FBI.')->warning();

            return back();
        }

    }
jlrdw's avatar

The above are validation errors. Not sure how are you are saying this is a permission issue.

Sorry I'm not understanding something.

I would still look at spatie examples.

trevorpan's avatar

hi, yea I've checked out their package, no views accompany the package.

My goal is for a user to have the option of choosing roles / permissions via html selects. I've been cracking my head to get to this point, but lack the experience.

The code I have checks the tables to see if the roles/permissions even exist. The goal is to prevent users from manipulating the values in the browser. If I'm not mistaken, you want this control.

Then it checks if a user via an html input for email exists.

If a user exists it checks if an administrator exists for that company, as only one admin can be on a company. Then it assigns the roles/permissions that the user has selected to that email (this can be themselves or someone else). It's pretty custom, but as Jeffrey said he likes to control this aspect of his site vs. a package.

Anyone else have an idea on how to implement this?

jlrdw's avatar

Typically an admin is going to assign roles and permissions, or an automated admin system.

An automated system would be like Express Scripts would have a system in place where a doctor would enter their credentials and if they match then credentials are created in the system.

Initial credentials I'm talking about DEA number and things like that.

I don't understand a user selecting roles from drop downs. An admin yes.

Of course a regular user would be automatically assigned just regular user kind of like you on the forum.

Have you looked at the let's build a forum, maybe Jeffrey uses roles and permissions there.

I haven't seen that one.

trevorpan's avatar

Hi @jlrdw ,

Well, I don't know what to say. I'd like someone who creates an account to be able to "claim" their company.

e.g. perhaps an employee finds BidBird and "invites" their boss. The boss may be older and not hip to the jive.

The roles and permissions, as noted in the form, are for the company. e.g. for the company to add or remove employees at will. The app will not want to dictate that or get in between those considerations.

It's entirely possible html selects are a dumb way to do this, but my OP is "Implementing a user interface for Roles & Permissions". Would really appreciate any ideas towards that end....

jlrdw's avatar

Well if this is more of a multi-tenant application which it sounds like, forgive me if I'm misunderstanding.

But you could try a search in Google like this copy and paste this


site:laracasts.com setting up multi-tenant roles and permissions

Change that search term that applies to your exact application.

Google search is more powerful than the one here.

Don't forget about stack overflow they have many good answers also.

trevorpan's avatar

It's not a multi-tenant. I would like to have the user select various roles/permissions from the dashboard.

Imagine ::::: company => has a user => who has a role => who then has permissions

I almost wonder if a pivot table should be a model???

The below seems like it would sabotage the attach() method and not really be using eloquent to it's finest.

//Here's a psuedo code.
$roleId = request('companyrole')->id;

$role = RolePermission::create([
    'role_id' => $roleId,
    'user_id' => auth->user()->id,
    ]);

any thoughts? how to escape the validation error and still use selects

jlrdw's avatar

Roles are usually assigned and matched via a pivot table.

Another way is a role field in the users table.

Bob may have 3 roles. I do a comma separated list and verify that a method that require a role as bookkeeper is one of Bob's roles. If it is he can edit bookkeeping. If a role doesn't match a redirect takes place.

Even Jeffrey said in a video that authorization is tricky to learn at first till you get more practice.

Search https://medium.com They have an article on Laravel authorization and roles permission management.

Sorry I saw it a while back, did not save the link. I like the comma separated list, but for larger apps most use a pivot table.

And you have viewed the videos, right? Because he covers all of this.

Edit found article:

https://medium.com/swlh/laravel-authorization-and-roles-permission-management-6d8f2043ea20

trevorpan's avatar
trevorpan
OP
Best Answer
Level 15

Hi @jlrdw , thank you for having a look here.

It was simpler than I thought - just removing required from $this->validate(request(), lifted that validation error as you first pointed out. The html5 required has been added to the html select elements for added browser validation.

After thinking about it for a while I recognized this controller is not storing the roles/permissions it's using the html selects to check against known roles/permissions and if that clears then the roles/permissions are attached using eloquent in the backend.

Do you, or anyone else, see any security flaws in this approach?

/**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $this->validate(request(), [
            'email' => 'string|email|max:255',
            'companyrole' => 'string|min:3',
            'companypermissions' => 'string|min:3',
        ]);

        $roleExists = Role::roleExists(request('companyrole'));
        $permissionExists = Permission::permissionExists(request('companypermissions'));

        if ($roleExists === true && $permissionExists === true) {

            $userExists = User::userExists(request('email'));
//            dd($userExists);
                if ($userExists) {

                    $companyHasAdministrator = Company::CompanyHasAdministratorRole(request('companyrole'));
    //                dd($companyHasAdministrator);
                    if ($companyHasAdministrator === false) {
//                        dd($userExists);
                        $role = Role::currentRole(request('companyrole'));
//                        dd($role);
                        $permission = Permission::currentPermission(request('companypermissions'));

                        $userExists->roles()->attach($role);
                        $role->givePermissionTo($permission);

                        flash('Thank you for adding roles and permissions.')->success();

                        return back();

                    } else {

                        flash('This company already has an administrator. Please select another role for that user.')->warning();

                        return back();
                    }

                } else {

                    flash('No one with that email exists. Would you please invite them in the Invitations Center below? After they accept you may add their roles and permissions.')->warning();

                    return back();

                }


        } else {

            flash('You have been reported to the FBI.')->warning();

            return back();
        }

Please or to participate in this conversation.