Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Shield Laravel Package

artesaos/shield

Artesaos Shield gives Laravel apps a lightweight authorization layer for roles and permissions. Define abilities once, assign them to users, and protect routes, controllers, and Blade views with simple, expressive checks.

View on GitHub
Deep Wiki
Context7

Getting Started

Start by confirming the package is installable in your Laravel version. artesaos/shield last shipped in 2016, so check its composer.json constraints before adding it to a real application. Use a scratch app or disposable branch first.

Minimal steps:

composer require artesaos/shield

# Publish config and migrations. Confirm the provider class from the package source.
php artisan vendor:publish --provider="Artesaos\Shield\ShieldServiceProvider"

php artisan migrate

Add the package trait to your authenticatable model:

use Artesaos\Shield\Traits\HasRoles; // verify exact namespace in vendor/artesaos/shield

class User extends Authenticatable
{
    use HasRoles;
}

Where to look first:

  1. config/shield.php — table names, model bindings, guard behaviour.
  2. database/migrations/ — role/permission pivot tables and foreign keys.
  3. src/ShieldServiceProvider.php — facade alias, middleware aliases, Blade directives, bindings.
  4. The facade class and traits — confirm actual method names; the README may be thinner than the source.

First use case: protect an admin route with a role.

// Seeder or tinker
$admin = Shield::createRole('admin');          // verify method name
$admin->givePermission('manage-users');        // verify method name

$user->assignRole('admin');                    // verify method name

Register the middleware alias if the package does not do it automatically:

// app/Http/Kernel.php
protected $routeMiddleware = [
    // ...
    'role' => \Artesaos\Shield\Middleware\RoleMiddleware::class,
    'permission' => \Artesaos\Shield\Middleware\PermissionMiddleware::class,
];
Route::group(['middleware' => ['role:admin']], function () {
    Route::get('/admin', AdminController::class . '@index');
});

Implementation Patterns

Treat roles as coarse job functions and permissions as fine-grained abilities. Seed both deterministically so every environment has the same canonical names.

// database/seeders/ShieldSeeder.php
Shield::createRole('admin');
Shield::createRole('editor');

Shield::createPermission('manage-users');
Shield::createPermission('edit-posts');
Shield::createPermission('publish-posts');

Shield::role('admin')->givePermission('manage-users');
Shield::role('editor')->givePermission('edit-posts');

Use the package API rather than direct pivot-table writes so caches and events stay consistent.

Assign roles through the user model:

$user->assignRole('editor');
$user->removeRole('editor');

Check access at the right layer:

// Route-level: middleware
Route::middleware('permission:edit-posts')->group(function () {
    Route::put('/posts/{post}', [PostController::class, 'update']);
});

// Controller-level: explicit authorization
public function update(Request $request, Post $post)
{
    abort_unless($request->user()->hasPermission('edit-posts'), 403);
    // ...
}

// Blade: presentation only
@role('admin')
    <a href="/admin">Admin</a>
@endrole

@permission('edit-posts')
    <a href="{{ route('posts.edit', $post) }}">Edit</a>
@endpermission

If the package registers permissions as gates, you can use Laravel’s native authorization:

// AuthServiceProvider
Gate::define('edit-posts', function ($user) {
    return $user->hasPermission('edit-posts');
});

// Controller
$this->authorize('edit-posts');

// Blade
@can('edit-posts')
    ...
@endcan

For policies, keep the package check inside the policy method so authorization remains centralised:

public function update(User $user, Post $post)
{
    return $user->hasPermission('edit-posts')
        && $post->author_id === $user->id;
}

Add a super-admin bypass once, not in every policy:

Gate::before(function ($user) {
    return $user->hasRole('super-admin') ? true : null;
});

Use eager loading when listing many users or rendering a permission-heavy page:

$users = User::with('roles.permissions')->paginate();

For route groups, prefer middleware over scattered checks:

Route::middleware(['auth', 'role:admin|super-admin'])->group(function () {
    // admin area
});

Gotchas and Tips

  • Age is the main risk. The package’s last release was 2016. It likely targets Laravel 5.x and older PHP versions. Do not assume it works on Laravel 9/10/11 or PHP 8.x without checking composer.json and running the migration and middleware paths end to end.
  • Unmaintained authorization code is security-sensitive. Auditing roles and permissions is not like auditing a view helper. If the package is abandoned, prefer Laravel’s Gate/Policy system or an actively maintained alternative such as spatie/laravel-permission.
  • Confirm the actual API before writing seeders. The package description promises a fluent API, Blade directives, and middleware, but the exact method names and directive syntax must be read from src/. Do not copy examples blindly.
  • Publish migrations before running them. Check for table-name collisions with existing roles, permissions, or pivot tables. Rename tables in config and migrations if needed.
  • Check the down() path. If the package owns tables, you need a safe rollback plan. Foreign-key constraints on pivot tables should be deliberate, especially for role deletion.
  • Guard mismatch. Roles and permissions are often tied to the default guard. If you use multiple guards (admin, api), verify that checks use the correct user and guard. A passing $user->hasRole() on the web guard does not automatically authorize an API guard user.
  • Permission caching can go stale. If the package caches roles or permissions, changing a role may not take effect until the cache is cleared. In long-running workers such as Octane, request-scoped state and caches need explicit review.
  • N+1 queries in loops. $user->hasPermission() inside a Blade loop or API resource can query repeatedly. Eager load roles.permissions and cache per-request results if the package does not.
  • Blade directives are not enforcement. @role and @permission hide UI; they do not protect routes or actions. Always enforce with middleware, authorize(), or a policy.
  • Facade and helper collisions. A global Shield alias or helper function can collide with your own code. Rename the alias in config/app.php if necessary.
  • Direct DB writes bypass package behaviour. Updating pivot tables manually may skip cache invalidation or events. Use the package’s assignment methods.
  • Config cache. After changing config/shield.php, run php artisan config:clear. If the package reads config during boot, a cached config can mask changes.
  • Debugging checks. Dump $user->roles, the exact permission string, and the guard. Permission names are case- and whitespace-sensitive. Verify middleware aliases with php artisan route:list.
  • Testing. Use RefreshDatabase, seed the roles and permissions your test needs, and assert both the happy path and the 403 path. Test middleware and policy paths separately.
  • Extension points. The description mentions configurable tables and models. If you need custom behaviour, publish the config, bind your own Role/Permission models, and extend the package models rather than editing vendor files. Keep the integration surface narrow so replacing the package later is feasible.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core