alfred-cerny/nette-security

Compile-time Nette DI access policy based on ComponentAttributes

Installs: 21

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/alfred-cerny/nette-security

0.0.4 2025-10-06 11:55 UTC

This package is auto-updated.

Last update: 2025-10-06 11:56:25 UTC


README

A robust access control system for Nette Framework applications, leveraging PHP 8+ attributes.

Features

  • Attribute-based Access Control: Define access requirements directly on Nette Components and their methods using PHP attributes.
  • Authentication Enforcement: Easily require user authentication for components or actions.
  • Role-based Access Control (RBAC): Restrict access based on user roles.
  • Resource-based Access Control: Implement fine-grained permissions for specific resources and privileges (e.g., ' edit' a 'post').
  • Seamless Nette Integration: Integrates with Nette DI and Nette Application lifecycle.
  • Extensible: Custom attributes can implement ComponentAttribute for extended access checks.

Installation

  1. Install via Composer:

    composer require alfred-cerny/nette-attributes
  2. Register the Nette DI Extension:

    In your config.neon (or common.neon), register the AccessPolicyExtension:

    extensions:
        accessPolicy: Alfred\Nette\Security\DI\AccessPolicyExtension
  3. Ensure your presenters are loaded in the DI

    application:
        scanDirs:
             - %appDir%/<path_to_your_application_src>

Usage

This library allows you to define access policies directly on your Nette Presenters, Components, and their methods using the #[Requires] attribute.

Requiring Authentication

To ensure a user is logged in to access a presenter or its methods:

use Alfred\Nette\Security\Attributes\Requires;
use Alfred\Nette\Security\UI\AccessPolicyAwarePresenter;

#[Requires(authentication: true)]
final class UserSettingsPresenter extends AccessPolicyAwarePresenter
{
    // ...
}

Role-based Access

To restrict access to specific roles:

use Alfred\Nette\Security\Attributes\Requires;
use Alfred\Nette\Security\UI\AccessPolicyAwarePresenter;

#[Requires(roles: 'admin')]
final class AdminPresenter extends AccessPolicyAwarePresenter
{
    // ...
}

// Multiple roles
#[Requires(roles: ['editor', 'publisher'])]
final class ContentPresenter extends AccessPolicyAwarePresenter
{
    // ...
}

Resource-based Access with Privileges

For more granular control, you can specify resources and privileges. This integrates with Nette's Nette\Security\User::isAllowed() method.

First, define your privileges using an enum (e.g., Alfred\Nette\Security\Enum\Privilege):

// src/Enum/Privilege.php
namespace App\Enum; // Or use Alfred\Nette\Security\Enum\Privilege;

enum Privilege: string
{
    case Create = 'create';
    case Read = 'read';
    case Update = 'update';
    case Delete = 'delete';
}

Then, use it in your presenter:

use Alfred\Nette\Security\Attributes\Requires;
use Alfred\Nette\Security\UI\AccessPolicyAwarePresenter;
use App\Enum\Privilege; // Assuming you defined your own Privilege enum

final class ArticlePresenter extends AccessPolicyAwarePresenter
{
    #[Requires(resources: ['article', Privilege::Read])]
    public function actionShow(int $id): void
    {
        // User must be allowed to 'read' the 'article' resource
    }

    #[Requires(resources: ['article', Privilege::Update])]
    public function actionEdit(int $id): void
    {
        // User must be allowed to 'update' the 'article' resource
    }

    // You can also specify just the resource, and the default privilege (if defined in your enum) will be used
    #[Requires(resources: 'dashboard')]
    public function renderDashboard(): void
    {
        // User must be allowed to 'dashboard' resource with default privilege
    }

    // Multiple resources/privileges
    #[Requires(resources: [['product', Privilege::Create], ['category', Privilege::Create]])]
    public function actionNewProduct(): void
    {
        // User must be allowed to create both 'product' and 'category'
    }
}

Applying to Methods

The #[Requires] attribute can also be applied to individual methods within a presenter or component:

use Alfred\Nette\Security\Attributes\Requires;
use Alfred\Nette\Security\UI\AccessPolicyAwarePresenter;
use App\Enum\Privilege;

final class ProductPresenter extends AccessPolicyAwarePresenter
{
    // This applies to all actions/renders in ProductPresenter
    #[Requires(authentication: true)]

    public function actionDefault(): void
    {
        // Accessible by any authenticated user
    }

    #[Requires(roles: 'manager')]
    public function actionManage(): void
    {
        // Accessible only by authenticated users with 'manager' role
    }

    #[Requires(resources: ['product', Privilege::Delete])]
    public function handleDelete(int $id): void
    {
        // Accessible only by authenticated users allowed to delete 'product'
    }
}

Customizing Unauthorized/Forbidden Responses

The Abstract\Requires class handles redirection for unauthenticated users and throws BadRequestException (403 Forbidden) for unauthorized roles/resources. You can override processUnauthorizedUser in a custom Requires attribute to change this behavior.

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

License

This project is licensed under the MIT License.