NovinkaZverejnili sme 50+ Laravel balíkov ako open source
Custom AI apps, agents and automation — Roundly ConsultingRoundly
Všetky balíky

RefreshTokens::fake() nahradí manažéra zaznamenávajúcim fake a vráti ho. Volania pritom stále bežia naozaj — tokeny sa vydávajú, uplatňujú a odvolávajú vo vašej testovacej databáze, pretože náhrada, ktorá by na redeem() odpovedala inak než skutočné úložisko, by nechala prejsť pokazený tok obnovy — a zaznamená sa každé volanie, či prišlo cez fasádu, injektovaný RefreshTokensManager, for()->issue(), sessions() / session() alebo trait HasRefreshTokens:

use RoundlyConsulting\RefreshTokens\Facades\RefreshTokens;

$fake = RefreshTokens::fake();

// … exercise your login / refresh / logout endpoints …

$fake->assertIssued(for: $user);
$fake->assertIssued($user, fn (IssueContext $context): bool => $context->accessReference === $jti);
$fake->assertRedeemed(by: $user);
$fake->assertRotated(for: $user);
$fake->assertRevoked(for: $user, reason: RevocationReason::CredentialsChanged);
$fake->assertEnriched(for: $user);
$fake->assertPruned();

$fake->assertNothingIssued();   // …and assertNothingRedeemed/Rotated/Revoked/Enriched/Pruned()
AserciaZachytí
assertIssued(?Model $for = null, ?Closure $where = null) / assertNothingIssued()issue(), for()->issue() a $owner->issueRefreshToken(); $where dostane IssueContext.
assertRedeemed(?Model $by = null) / assertNothingRedeemed()redeem() — neúspešné uplatnenie sa zaznamená bez vlastníka.
assertRotated(?Model $for = null) / assertNothingRotated()rotate() — zaznamená sa len ako rotácia, nie aj ako uplatnenie a vydanie.
assertRevoked(?Model $for = null, ?RevocationReason $reason = null) / assertNothingRevoked()revoke($plain), každé sessions()->revoke…(), session()->revoke() a metódy traitu na odvolanie.
assertEnriched(?Model $for = null) / assertNothingEnriched()session()->enrich().
assertPruned() / assertNothingPruned()prune() a príkaz refresh-tokens:prune.
recorded()Všetky volania ako RecordedOperation (operation, owner, reason, context, count).

Volanie, ktoré vyhodí výnimku, sa nezaznamená. Asercie používajú PHPUnit Assert.

Odvolanie prístupových tokenov

Namiesto skutočného revokera zaregistrujte dodaný FakeAccessTokenRevoker a overte presne, ktoré odkazy na prístupové tokeny balík žiadal zneplatniť — bez vlastného spy objektu:

use RoundlyConsulting\RefreshTokens\Contracts\AccessTokenRevoker;
use RoundlyConsulting\RefreshTokens\Testing\FakeAccessTokenRevoker;

$revoker = new FakeAccessTokenRevoker();
$this->app->instance(AccessTokenRevoker::class, $revoker);

// … exercise reuse detection / session revocation …

$revoker->assertRevoked($jti);
$revoker->assertNotRevoked($otherJti);
$revoker->assertRevokedCount(2);
$revoker->assertNothingRevoked();   // when nothing should have been denied

Jeho asercie vyhadzujú RevokerAssertionFailedException namiesto PHPUnit asercie, takže funguje v akomkoľvek test runneri.

Kompletný test detekcie opätovného použitia

use Illuminate\Support\Facades\Event;
use RoundlyConsulting\RefreshTokens\Contracts\AccessTokenRevoker;
use RoundlyConsulting\RefreshTokens\DataTransferObjects\IssueContext;
use RoundlyConsulting\RefreshTokens\DataTransferObjects\RotationContext;
use RoundlyConsulting\RefreshTokens\Events\RefreshTokenReuseDetected;
use RoundlyConsulting\RefreshTokens\Facades\RefreshTokens;
use RoundlyConsulting\RefreshTokens\Testing\FakeAccessTokenRevoker;

it('revokes the whole family when a rotated token is reused', function () {
    Event::fake([RefreshTokenReuseDetected::class]);
    $revoker = new FakeAccessTokenRevoker();
    $this->app->instance(AccessTokenRevoker::class, $revoker);

    $user = User::factory()->create();
    $a = RefreshTokens::issue($user, new IssueContext(accessReference: 'acc-a'));
    RefreshTokens::rotate($a->plainText, new RotationContext(accessReference: 'acc-b'));

    expect(RefreshTokens::redeem($a->plainText))->toBeNull(); // replay = theft signal

    $revoker->assertRevoked('acc-b');
    $revoker->assertRevokedCount(1);
    Event::assertDispatchedTimes(RefreshTokenReuseDetected::class, 1);
});

Factory

Model RefreshToken má factory so stavmi expired(), revoked($reason), forFamily($id) a forOwner($owner):

use RoundlyConsulting\RefreshTokens\Enums\RevocationReason;
use RoundlyConsulting\RefreshTokens\Models\RefreshToken;

RefreshToken::factory()->forOwner($user)->create();                         // a live session row
RefreshToken::factory()->forOwner($user)->expired()->create();
RefreshToken::factory()->forOwner($user)->revoked(RevocationReason::Logout)->create();
RefreshToken::factory()->forOwner($user)->forFamily($familyId)->create();

Riadky z factory majú náhodný odtlačok, nikdy skutočný plaintext, takže sa nedajú uplatniť — použite ich na testy výpisu, odvolania a čistenia a issue(), keď potrebujete token, ktorý sa dá uplatniť.

Vlastné testy balíka

composer test
composer test-coverage

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

Odoslaním daru súhlasíte s našimi podmienkami prijímania darov.

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.