---
title: "Rozšírenie — Sentinel for Laravel | Roundly"
description: "Zapojte úložisko kľúčov v KMS alebo vlastnú kotvu a naviažte vlastné úložiská idempotencie a nonce, scope resolver či politiku potvrdenia."
url: https://roundly-consulting.com/sk/open-source/navody/sentinel-for-laravel/rozsirenie
language: sk
---

[Všetky balíky](https://roundly-consulting.com/sk/open-source.md)

[Sentinel for Laravel](https://roundly-consulting.com/sk/open-source/navody/sentinel-for-laravel.md)

# Rozšírenie

Každý bod rozšírenia je kontrakt v RoundlyConsulting\\Sentinel\\Contracts, ktorý sa získava z kontajnera — Sentinel::fake() aj prepisy v aplikácii teda fungujú ďalej. Drivery registrujte v metóde boot() service providera:

```php
use Illuminate\Contracts\Container\Container;
use RoundlyConsulting\Sentinel\Contracts\Anchor;
use RoundlyConsulting\Sentinel\Contracts\KeyStore;

// A key-store driver (e.g. a KMS): name it in keys.rings.<ring>.driver.
Sentinel::extend('vault', fn (Container $app, string $ring, array $config): KeyStore => new VaultKeyStore($ring, $config));

// An anchor: name it in SENTINEL_ANCHORS.
Sentinel::extendAnchor('s3-lock', fn (Container $app, array $config): Anchor => new ObjectLockAnchor($config));
```

| Kontrakt | Metódy | Predvolené / napojenie |
| --- | --- | --- |
| `Contracts\KeyStore` | `signingKey(): SealingKey, find(string $keyId): ?SealingKey, all(): list<KeyInfo>, supportsWrites(): bool` | config, database, chain; vlastný cez Sentinel::extend() |
| `Contracts\Anchor` | `name(): string, publish(AnchorPayload $payload): void, latest(string $connection): ?AnchorPayload` | cache, filesystem, log; vlastná cez Sentinel::extendAnchor() (kotva len na zápis vracia z latest() null a implementuje značku Contracts\\WriteOnlyAnchor) |
| `Contracts\IdempotencyStore` | `begin(), complete(), release(), forget(), prune()` | podľa idempotency.store |
| `Contracts\NonceStore` | `issue(), consume(), remember(), prune()` | podľa nonces.store |
| `Contracts\IdempotencyScopeResolver` | `resolve(Request $request): string` | Idempotency\\RequestScope (používateľ, inak kľúč podpisu, inak IP) |
| `Contracts\AcknowledgementPolicy` | `authorize(AcknowledgeRequest $request): ?string` | Gate kontrola acknowledgement.ability (null = povolené, inak kód zamietnutia) |
| `Contracts\SealDefinition` | `define(SealDefinitionBuilder $seal): void` | \->using(MyDefinition::class) |
| `Contracts\Sealable` | `static defineSeals(SealBuilder $seals): void` | vaše modely s HasSeals |

## Úložiská kľúčov (KMS, Vault, HSM)

```php
// config/sentinel.php
'keys' => ['rings' => ['financial' => ['driver' => 'vault', 'algorithms' => ['ed25519']]]],

interface KeyStore
{
    public function signingKey(): SealingKey;          // NoSigningKeyException when none
    public function find(string $keyId): ?SealingKey;  // any status; null when unknown
    /** @return list<KeyInfo> */
    public function all(): array;
    public function supportsWrites(): bool;            // false: generate/rotate print env lines
}
```

Kľúče zostavujte cez verejné rozhranie na rozšírenie. KeyMaterial overí materiál presne tak ako vstavané drivery a drží ho mimo výpisov aj serializácie (fromEncoded(), generate(), canSign(), encodedPrivate(), encodedPublic()); vracajte inštancie SealingKey s ich efektívnym stavom. Manažér nad každým driverom uplatní zoznam odvolaní — v kruhu chain sa odvolaný podpisový kľúč vlastného úložiska preskočí a podpisuje ďalšie úložisko, rovnako ako pri vstavaných driveroch — a kľúče cachuje len v rámci požiadavky či jobu.

```php
use RoundlyConsulting\Sentinel\Enums\Algorithm;
use RoundlyConsulting\Sentinel\Enums\KeyStatus;
use RoundlyConsulting\Sentinel\Keys\KeyMaterial;
use RoundlyConsulting\Sentinel\Keys\SealingKey;

$material = KeyMaterial::fromEncoded(Algorithm::Ed25519, $secretFromVault, $publicFromVault);   // base64:… values

return new SealingKey($ring, 'vault-2026-10', $material, KeyStatus::Active, driver: 'vault');
```

Sentinel zapisuje kľúče (generovanie, rotácia, import, odvolanie, vyradenie) len do vstavaného databázového úložiska kruhu — kruh len s vlastným driverom je pre neho len na čítanie; ak chcete importovať kľúče partnerov za behu, zreťazte vlastný driver s database. Kým kruh podpisuje kľúčom vlastného drivera (samostatne alebo ako prvý v reťazi), rotateKey() aj sentinel:key:rotate odmietnu s KeyDriverException: rotujte ten kľúč v jeho vlastnom úložisku — Sentinel materiál vlastného úložiska nikdy nevypíše.

## Kotvy

```php
use RoundlyConsulting\Sentinel\Contracts\Anchor;
use RoundlyConsulting\Sentinel\DataTransferObjects\AnchorPayload;

final class ObjectLockAnchor implements Anchor
{
    public function name(): string { return 's3-lock'; }

    public function publish(AnchorPayload $payload): void { /* write it immutably */ }

    public function latest(string $connection): ?AnchorPayload { /* what the anchor really holds */ }
}
```

Uveďte ju v SENTINEL\_ANCHORS=s3-lock; jej voľby patria do ledger.anchor\_drivers.s3-lock. Publikovanie beží po commite; výnimka sa zmení na AnchorPublishFailed a ďalší beh to skúsi znova — okrem InvalidSentinelConfigurationException, ktorá sa vyhodí. Ak vaše úložisko obsah neuložilo, vyhoďte výnimku (vstavané drivery vyhodia AnchorPublishException::notWritten(), keď disk alebo cache vráti false). Pred publikovaním Sentinel prečíta latest() a odmietne nahradiť obsah, s ktorým databáza už nesúhlasí, preto latest() musí vrátiť to, čo kotva naozaj drží.

Kotva len na zápis (log odosielaný inam, notár, ktorého sa nedá spýtať) vracia z latest() null a implementuje značku Contracts\\WriteOnlyAnchor — inak by beh, v ktorom nič nečaká, chápal null ako „nič nedrží“ a každú minútu by jej znova posielal najnovší kontrolný bod:

```php
use RoundlyConsulting\Sentinel\Contracts\WriteOnlyAnchor;

final class NotaryAnchor implements WriteOnlyAnchor
{
    public function name(): string { return 'notary'; }

    public function publish(AnchorPayload $payload): void { /* send it */ }

    public function latest(string $connection): ?AnchorPayload { return null; }
}
```

## Úložiská idempotencie a nonce

```php
use RoundlyConsulting\Sentinel\Contracts\IdempotencyStore;
use RoundlyConsulting\Sentinel\Contracts\NonceStore;

$this->app->bind(IdempotencyStore::class, DynamoIdempotencyStore::class);
$this->app->bind(NonceStore::class, DynamoNonceStore::class);
```

Úložisko idempotencie musí mať begin() atomické pre každý kľúč — zo súbežných volaní dostane Proceed práve jedno — a dodržať rozhodovaciu tabuľku: iný odtlačok → Reused, platný lease → InProgress s retryAfter, vypršaný lease → prevzatie, dokončené → Replay alebo Unavailable. complete() uspeje len vtedy, kým požiadavka kľúč stále vlastní; consume() a remember() uspejú pre práve jedného volajúceho; upravené či nečitateľné záznamy zlyhajú bezpečne. InMemoryIdempotencyStore a InMemoryNonceStore z fake sú kompaktné referenčné implementácie.

## Scope idempotencie

Predvolený Idempotency\\RequestScope vráti user:<guard>:<id>, inak sig:<ring>:<kid>, inak ip:<client ip> a kľúč sa ďalej viaže na routu. Ak chcete zmeniť prvú časť, naviažte kontrakt znova:

```php
use Illuminate\Http\Request;
use RoundlyConsulting\Sentinel\Contracts\IdempotencyScopeResolver;

final class TenantScope implements IdempotencyScopeResolver
{
    public function resolve(Request $request): string
    {
        return 'tenant:'.$request->user()?->tenant_id.':user:'.$request->user()?->getKey();
    }
}

$this->app->bind(IdempotencyScopeResolver::class, TenantScope::class);
```

## Politika potvrdenia

```php
use RoundlyConsulting\Sentinel\Contracts\AcknowledgementPolicy;
use RoundlyConsulting\Sentinel\DataTransferObjects\AcknowledgeRequest;

final class TwoPersonRule implements AcknowledgementPolicy
{
    public function authorize(AcknowledgeRequest $request): ?string   // null = allowed, else a denial code
    {
        return Approval::grantedFor($request->model, $request->seal, $request->actor) ? null : 'approval_required';
    }
}

$this->app->bind(AcknowledgementPolicy::class, TwoPersonRule::class);
```

Zamietnutie vyhodí AcknowledgementDeniedException::unauthorized($code) — rovnako cez fasádu, handle, hromadné potvrdenia aj sentinel:reseal --acknowledge.

## Predvolené naviazania

| Kontrakt / služba | Predvolené | Životnosť |
| --- | --- | --- |
| `SentinelManager` | on sám | singleton |
| `Contracts\AcknowledgementPolicy` | `Support\GateAcknowledgementPolicy` | bindIf — vyhrá vaše naviazanie |
| `Contracts\IdempotencyScopeResolver` | `Idempotency\RequestScope` | bindIf |
| `Contracts\IdempotencyStore` | podľa idempotency.store (database / cache) | pri každom použití; naviazanie v aplikácii ho nahradí |
| `Contracts\NonceStore` | podľa nonces.store (database / cache) | pri každom použití; naviazanie v aplikácii ho nahradí |
| továrne úložísk kľúčov a kotiev, skompilované definície | — | singletony (len kód, žiadny materiál kľúčov) |
| načítané kľúče, príznaky pozastavenia, služby enginu | — | scoped: jedna požiadavka alebo job (bezpečné pre Octane) |

Manažér si akciu vezme z kontajnera pri každom volaní, takže naviazanie triedy akcie v kontajneri platí všade.

## Prejavte lásku k open source

Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.

[Ďalšie spôsoby podpory vrátane kryptomien](https://roundly-consulting.com/sk/podporte-nas.md)

Odoslaním daru súhlasíte s našimi [podmienkami prijímania darov](https://roundly-consulting.com/sk/podmienky-darov.md).

[Podporte našu open-source prácu (otvorí sa v novej karte)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Pridajte sa k nám na Patreone (otvorí sa v novej karte)](https://www.patreon.com/cw/roundly)

## Chcete to zabudovať do svojho produktu?

Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.

[Ponuka do 48 hodín](https://roundly-consulting.com/sk/kontakt.md) [Prezrieť všetky balíky](https://roundly-consulting.com/sk/open-source/navody/sentinel-for-laravel.md)
