Authority

Role Based Access Control bundle for Laravel

Welcome to Authority for Laravel.

This is a clone from codeigniter-authority-authorization Check https://github.com/machuga/codeigniter-authority-authorization for more info. All credits go to machuga for PHP-izing this awesome library

Installation

$ cd to/your/project/root/
$ php artisan bundle:install authority
$ php artisan migrate:install

Before we can run the migration, you will have to register the bundle as seen below.

return array(
    'authority' => array(
        'auto' => true
    )
)

Now we can run authority's migration to setup the tables

$ php artisan migrate authority

Since we don't want updates (via artisan, Laravel's CLI) to break our configuration later, we move the config outside of the Authority bundle.

If you want your authority config to live in another bundle, you have to point to that location by changing the location in bundles/authority/authority.php.

Configuring the Auth driver

Open up application/config/auth.php and change the value of "driver" to "eloquent"

Adding the models

User model

application/models/user.php

class User extends Eloquent {

    public static $timestamps = true;

    public function roles()
    {
        return $this->has_many_and_belongs_to('Role', 'role_user');
    }

    public function has_role($key)
    {
        foreach($this->roles as $role)
        {
            if($role->name == $key)
            {
                return true;
            }
        }

        return false;
    }

    public function has_any_role($keys)
    {
        if( ! is_array($keys))
        {
            $keys = func_get_args();
        }

        foreach($this->roles as $role)
        {
            if(in_array($role->name, $keys))
            {
                return true;
            }
        }

        return false;
    }
}

Role model

application/models/role.php

class Role extends Eloquent {

    public function users()
    {
        return $this->has_many_and_belongs_to('User');
    }

}

Using Authority

Authority is very flexible, allowing you to make complex rules, load permissions from different places, and make handy action aliases.

Before we can use Authority, we need to understand how it works. In order to understand how it works, we have to be aware of some concepts.

Actions

Resources

Rules

Allow

Deny

Now that we are familiar with these concepts, let's dive into some example configurations.

    'initialize' => function($user)
    {
        // The initialize method (this Closure function) will be ran on every page load when the bundle get's started.
        // A User Object will be passed into this method and is available via $user
        // The $user variable is a instantiated User Object (application/models/user.php)

        // First, let's group together some "Actions" so we can later give a User access to multiple actions at once
        Authority::action_alias('manage', array('create', 'read', 'update', 'delete'));
        Authority::action_alias('moderate', array('update', 'delete'));

        // If a user doesn't have any roles, we don't have to give him permissions so we can stop right here.
        if(count($user->roles) == 0) return false;

        // Let's say we want to "Deny" the User from adding accounts if his age is below 21 (i don't mean to discriminate ;) 
        // Since we have the User object, and it has an "age" property, we can make a simple if statement.
        if($user->age < 21)
        {
            // Too young! we "deny" the user to create users, i'm sorry...
            Authority::deny('create', 'User');
        }

        if($user->has_role('admin'))
        {
            // The logged in user is an admin, we allow him to perform manage actions (create, read, update, delete) on "all" "Resources".
            Authority::allow('manage', 'all');

            // Let's make it a little harder, we don't want the admin to be able to delete his own User account, but has to be allowed to delete other Users.
            // We only know that the "Resource" is a User, But we don't know the User id, we can send that information to the Rule Closure, in the Closure below, the argument is called $that_user.
            // We also pass in the logged in user, since the Closure is outside of the scope where this comment is in.
            Authority::deny('delete', 'User', function ($that_user) use ($user)
            {
                // If the id of the User that we are trying to delete is equal to our logged in user, we return true, meaning the Deny Rule will be set.
                return $that_user->id == $user->id;
            });
        }

        if($user->has_role('store_owner'))
        {
            // What if the logged in User has the role "store_owner", let's allow the user to manage his own store
            Authority::allow('manage', 'Store', function($store) use ($user)
            {
                return ! is_null(DB::table('stores')->where_id($store->id)->where_user_id($user->id)->first());
            });
        }

        // We can set Allow and Deny Rules by looping through results we get from somewhere else, in this example, a database
        foreach(DB::table('rules')->where_user_id($user->id)->get() as $permission)
        {
            if($permission->type == 'allow')
            {
                Authority::allow($permission->action, $permission->resource);
            }
            else
            {
                Authority::deny($permission->action, $permission->resource);
            }
        }
    }

Now that we have the initialize method setup, we can do checks throughout our code (controllers/models/views) like this

    // in some controller
    if(Authority::cannot('create', 'User'))
    {
        Redirect::to('home');
    }

    // in some view
    <?php if(Authority::can('edit', 'User')): ?>
        <?php echo HTML::link('users/edit/'.$user->id, 'Edit User'); ?>
    <?php endif ?>

    // In some model
    $user = User::find($id);
    if(Authority::can('delete', 'User', $user))
    {
        $user->delete();
    }

Support or Contact

Having trouble with Authority? Find me in the #laravel IRC channel or contact me @ k.schmeets@gmail.com and i’ll help you sort it out.

A big Thanks

To (@ryanb) for making CanCan

To (@machuga) for porting CanCan to PHP