Git Product home page Git Product logo

authorization's Introduction

Authorization

Build Status Scrutinizer Code Quality Total Downloads Latest Stable Version License

An easy, native role / permission management system for Laravel.

Authorization automatically adds your database permissions and roles to the Illuminate\Auth\Access\Gate, this means that you can utilize all native laravel policies and methods for authorization.

This also means you're not walled into using this package if you decide it's not for you.

Installation

Insert Authorization in your composer.json file:

"larapacks/authorization": "1.1.*"

Then run composer update.

Insert the service provider in your config/app.php file:

Larapacks\Authorization\AuthorizationServiceProvider::class,

Once that's complete, publish the migrations using:

php artisan vendor:publish --tag="authorization"

Then run php artisan migrate.

Once you've done the migrations, create the following two models and insert the relevant trait:

The Role model:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Larapacks\Authorization\Traits\RolePermissionsTrait;

class Role extends Model
{
    use RolePermissionsTrait;
}

The Permission model:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Larapacks\Authorization\Traits\PermissionRolesTrait;

class Permission extends Model
{
    use PermissionRolesTrait;
}

Now insert the Larapacks\Authorization\Traits\UserRolesTrait onto your App\User model:

namespace App;

use Larapacks\Authorization\Traits\UserRolesTrait;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use UserRolesTrait;
    
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];
}

You're all set!

Usage

Using authorization is easy, because it's utilizing native laravel relationships.

Create a permission:

$createUsers = new Permission();

$createUsers->name = 'users.create';
$createUsers->label = 'Create Users';

$createUsers->save();

Grant the permission to a role:

$administrator = new Role();

$administrator->name = 'administrator';
$administrator->label = 'Admin';

$administrator->save();

$administrator->permissions()->save($createUsers);

Now assign the role to the user:

$user->roles()->save($administrator);

You can also create user specific permissions:

$createUsers = new Permission();

$createUsers->name = 'users.create';
$createUsers->label = 'Create Users';

$createUsers->save();

$user->permissions()->save($createUsers);

Performing Authorization (Native)

// Using Laravel's native `can()` method:

if ($user->can('users.create')) {
    // This user can create other users.
}

// Using Laravel's native `authorize()` method in your controllers:

public function create()
{
    $this->authorize('users.create');
    
    User::create(['...']);
}

// Using Laravel's native Gate facade:

if (Gate::allows('users.create')) {
    //
}

// Using Laravel's native `@can` directive in your views:

@can('users.create')
    <!-- This user can create other users. -->
@endcan

Performing Authorization (Package Specific)

Checking for permission:

// Using the permissions name.
if ($user->hasPermission('users.create')) {
    //
}

// Using the permissions model.
if ($user->hasPermission($createUsers)) {
    //
}

Checking for multiple permissions:

if (auth()->user()->hasPermissions(['users.create', 'users.edit'])) {
    // This user has both creation and edit rights.
} else {
    // It looks like the user doesn't have one of the specified permissions.
}

Checking if the user has any permissions:

if (auth()->user()->hasAnyPermissions(['users.create', 'users.edit', 'users.destroy'])) {
    // This user either has create, edit or destroy permissions.
} else {
    // It looks like the user doesn't have any of the specified permissions.
}

Checking if the user has a role:

if (auth()->user()->hasRole('administrator')) {
    // This user is an administrator.
} else {
    // It looks like the user isn't an administrator.
}

Checking if the user has specified roles:

if (auth()->user()->hasRoles(['administrator', 'member'])) {
    // This user is an administrator and a member.
} else {
    // It looks like the user isn't an administrator or member.
}

Checking if the user has any specified roles:

if (auth()->user()->hasAnyRoles(['administrator', 'member', 'guest'])) {
    // This user is either an administrator, member or guest.
} else {
    // It looks like the user doesn't have any of these roles.
}

Middleware

Authorization includes two useful middleware classes you can utilize for your routes.

Insert them into your app/Http/Kernel.php:

/**
 * The application's route middleware.
 *
 * These middleware may be assigned to groups or used individually.
 *
 * @var array
 */
protected $routeMiddleware = [
    'auth' => \App\Http\Middleware\Authenticate::class,
    'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
    'permission' => \Larapacks\Authorization\Middleware\PermissionMiddleware::class, // The permission middleware
    'role' => \Larapacks\Authorization\Middleware\RoleMiddleware::class, // The role middleware
];

Once you've done that, you can start using them.

Note: When a user does not meet the requirements using the middleware, a 403 HTTP exception is thrown.

To guard a route to only allow specific permissions:

Route::get('users', [
    'uses' => 'UsersController@index',
    'middleware' => 'permission:users.index',
]);

// Multiple permissions:
Route::get('users', [
    'uses' => 'UsersController@index',
    'middleware' => 'permission:users.index,users.create', // Users must have index **and** create rights to access this route.
]);

To guard a route to allow a specific role:

Route::get('users', [
    'uses' => 'UsersController@index',
    'middleware' => 'role:administrator',
]);

// Multiple roles:
Route::get('users', [
    'uses' => 'UsersController@index',
    'middleware' => 'role:administrator,member', // Users must be an administrator **and** a member to access this route.
]);

Closure Permissions

Note: This feature was introduced in v1.1.0.

Problem:

You need database permissions but you need logic in some permissions as well.

For example, if a user creates a post, only that user should be able to edit it, as well as administrators.

To include this logic into gate abilities, your options are:

  • Define gate abilities in the service provider with the logic (which can get cluttered and become an organizational mess)
  • Define policy classes and have a mix of database abilities with policies (more mess)
  • Policies then need to be bound to a model, and if we don't have a model, we need to call the policy() helper method, and throw our own authorization exception (more confusion)

Solution:

Store all abilities in the database including ones that require logic and utilize native laravel methods for all authorization.

Here's how it's done:

// Create the closure permission

$permission = new Permission();

$permission->name = "posts.edit";
$permission->label = "Edit Posts";
$permission->closure = function ($user, $post) {
    return $user->id == $post->user_id || $user->hasRole('admin');
};

$permission->save();

Use native laravel authorization:

public function edit($id)
{
    $post = Post::findOrFail($id);
    
    $this->authorize('posts.edit', [$post]);
    
    return view('posts.edit', compact('post'));
}

It's not necessary to save the permission onto the user because the logic is inside the permission itself to determine whether or not the user can perform the ability.

That's great and all, but I need access to be able to bypass these checks if the user is an administrator!

No problem, just go into your native app/Providers/AuthServiceProvider and define that explicitly in the gate.

public function boot(GateContract $gate)
{
    $this->registerPolicies($gate);
    
    $gate->before(function ($user) {
        return ($user->hasRole('administrator') ?: null);
    });
}

Now all your dynamic logic is stored inside the database, and your clean logic is stored inside the AuthServiceProvider.

Neat huh?

Running Tests

To run your applications tests, inside your TestCase::setUp() method, you'll instantiate the PermissionRegistrar before running your tests for permissions to register properly:

use Larapacks\Authorization\PermissionRegistrar;
public function setUp()
{
    parent::setUp();
    
    $registrar = app(PermissionResistrar::class);
    
    $registrar->register();
}

authorization's People

Contributors

ikilled avatar stevebauman avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.