Enterprise sürüm
SaaS — Derinlemesine başvuru
Bir bakışta
“Bir bakışta” başlıklı bölümEnterprise SaaS modülü, NextPDF tabanlı bir hizmet için çok kiracılı yapı taşlarını sağlar.
TenantContext, yalnızca kimliği doğrulanmış bağlamdan çözümlenen, değişmez bir kimlik değer nesnesidir.ApiKeyGeneratorveApiKeyAuthenticator, önekli, sağlama toplamlı ve karma olarak saklanan API anahtarlarını üretir ve doğrular.QuotaChecker, istekleri kiracı başına kotalara göre geçitler: %80’de uyarır, %100’de reddeder, kullanım bilinmediğinde fail-closed olarak reddeder.SidecarJwtMinter, bileşenler arası çağrılar için kısa ömürlü HS256 hizmet token’ları üretir.UsageMeterveStripeMeteringSyncer, kullanım olaylarını çeker ve bunları belirlenimci idempotensi ile faturalama sağlayıcısına eşitler.
Kullanılabilirlik ve lisanslama
“Kullanılabilirlik ve lisanslama” başlıklı bölümBu yetenek NextPDF Enterprise (nextpdf/enterprise) içinde sevk edilir ve Enterprise katmanı lisans zarfıyla etkinleşir. Bu yetkilendirmeye sahip olmayan bir dağıtım, yeteneğin sınıflarını yüklemez. Sürümleri karşılaştırın ve lisans alın.
SaaS yüzeyi temel bir Enterprise yeteneğidir; özellik başına ayrı bir bayrak yoktur. NextPDF Core (Apache-2.0) ve NextPDF Pro’nun kiracılık, API anahtarı veya kota modeli yoktur; bu yeteneğin daha alt katmanda bir eşdeğeri yoktur.
composer require nextpdf/enterprise:^3Genel API yüzeyi
“Genel API yüzeyi” başlıklı bölümTüm semboller NextPDF\Enterprise\SaaS altında yer alır.
| Sembol | Parametreler | Varsayılan davranış | Döndürür | Fırlatır veya şununla başarısız olur | Notlar |
|---|---|---|---|---|---|
TenantContext | string $tenantId, string $source, array $scopes = ['read'] | Değişmez kimlik değer nesnesi | değer nesnesi | Yok | Kaynaklar: jwt, mtls, api_key; hasScope() / hasAnyScope() kapsamları test eder |
TenantContext::singleTenant() | yok | read, write, admin ile sabit default kiracı | TenantContext | Yok | Tek kiracılı dağıtımlar |
ApiKeyAuthenticator::authenticate() | string $rawKey | Altı adımlı doğrulama, ardından bağlam çözümleme | TenantContext | ApiKeyAuthenticationException (HTTP 401) | Bağlam source değeri api_key’dir; kapsamlar anahtar kaydından kopyalanır |
ApiKeyAuthenticator::requireScope() | TenantContext $context, ApiKeyScope $requiredScope | Açık kapsam doğrulaması | void | ApiKeyAuthenticationException::insufficientScope() (HTTP 403) | Kapsam zorlaması ayrı, açık bir adımdır |
ApiKeyGenerator::generateLive() / ::generateTest() | yok | Yeni anahtar: önek, 32 karakterlik base62 gövde (192 bit entropi), 4 karakterlik sağlama toplamı | array{key, hash, prefix} | Yok | Önekler npf_live_ / npf_test_; hash depolama özetidir |
ApiKeyGenerator::validateChecksum() | string $key | Önek, uzunluk ve CRC32 sağlama toplamı biçim denetimi | bool | Yok | Herhangi bir veri deposu aramasından önce yazım hatası koruması; bir güvenlik denetimi değil |
ApiKeyGenerator::hashKey() (statik) | string $key | Ham anahtarın SHA-256 onaltılık özeti | string | Yok | Bir anahtarın saklanan tek gösterimi |
ApiKeyGenerator::isLiveKey() / ::isTestKey() | string $key | Önek incelemesi | bool | Yok | Ortam, bir arama olmadan görünür |
ApiKey | kimlik, kiracı, anahtar karması, görüntü öneki, kapsam maskesi, oluşturma/sona erme/iptal anları | Saklanan anahtar kaydı; düz metin asla kalıcılaştırılmaz | değer nesnesi | Yok | isActive(), isRevoked(), isExpired(), scopeNames() |
ApiKeyScope | destekli enum: Read = 1, Write = 2, Admin = 4 | Bit maskesi kapsam modeli | enum | Yok | maskFromNames(), fromName(), fullAccess(); bilinmeyen adlar maske oluşturucu tarafından yok sayılır |
ApiKeyRepositoryInterface | — | Depolama sözleşmesi; yalnızca karma kalıcılaştırma | — | Uygulama tanımlı | findByHash(), findActiveByTenant(), store(), revoke() |
SidecarJwtMinter::__construct() | string $secret, issuer, audience, int $ttlSeconds = 300 | Yapım sırasında 16 bayttan küçük bir imzalama sırrını reddeder | örnek | InvalidArgumentException | 128 bit anahtar-gücü tabanı; 32 veya daha fazla rastgele bayt önerilir |
SidecarJwtMinter::mint() | TenantContext $tenant | iss, aud, sub, scope, tenant_id, iat, exp, jti içeren HS256 JWT | string | Talep kodlama başarısızlığında JsonException | Beş dakikalık varsayılan ömür; jti, onaltılık kodlanmış 16 rastgele bayttır |
QuotaChecker::check() | TenantContext $tenant, TenantQuota $quota | Geçerli kullanımı okur; %80’de uyarır; %100’de reddeder; kullanım bilinmediğinde reddeder | array{allowed: bool, warning_percentage: float|null} | QuotaExceededException, QuotaUnavailableException | Uyarı geri çağrısı her iki eşikte de çağrılır |
TenantQuota | float $maxCuPerPeriod, koleksiyonlar, depolama baytları, eşzamanlı işler | Dönem başına limitler; %80 yumuşak eşik sabiti | değer nesnesi | Yok | fromConfig() varsayılanları: 10,000 CU, 100 koleksiyon, 10 GB, 10 iş |
QuotaExceededException::toErrorEnvelope() | yok | SPEC-QUOTA-001 hata zarfı | array | — | HTTP 402, yeniden denenebilir değil; geçerli değeri, limiti ve sıfırlama anını taşır |
QuotaUnavailableException::toErrorEnvelope() | yok | SPEC-QUOTA-503 hata zarfı | array | — | HTTP 503, yeniden denenebilir; neden usage_undeterminable |
UsageMeter::pullUsage() | array<string, int> $watermarks | Yapılandırılmış her kullanım-kaynağı ana makinesini imlecinden yoklar | array{events, instance_id} | Her ana makine erişilemez olduğunda UsageMeterException | Kısmi kesinti tolere edilir; erişilemeyen ana makineler günlüğe kaydedilir ve atlanır |
UsageMeter::getCurrentUsage() | string $tenantId | Geçerli dönem hesaplama-birimi kullanımı | float | Kullanım belirlenemez olduğunda UsageMeterException | Ayrıştırılabilir bir sıfır yetkilidir; bilinmeyen kullanım fırlatır |
StripeMeteringSyncer::sync() | array<string, int> $watermarks | Bir çekme, dönüştürme, gönderme döngüsü | array{watermarks, sent, failed} | Yok; gönderme başarısızlıkları DLQ geri çağrısına yönlendirilir | Çekme başarısızlığı, imleci koruyan işlemsiz bir döngü döndürür |
StripeAdapter::sendMeterEvent() | MeterEvent $event | Bir idempotensi başlığıyla sağlayıcıya POST | void | StripeSyncException | HTTP 429 ve 5xx yeniden denenebilir; diğer 4xx yeniden denenebilir değil |
StripeAdapter::sendBatch() | list<MeterEvent> $events | Her olayı gönderir; başarısızlıkları toplar | list<StripeSyncException> | Yok | Boş liste, her olayın başarılı olduğu anlamına gelir |
MeterEvent | ölçer adı, kiracı, değer, idempotensi anahtarı, zaman damgası | Değişmez ölçer-olayı değer nesnesi | değer nesnesi | Yok | toStripePayload(), sağlayıcı yükünü serileştirir |
final readonly class ApiKeyAuthenticator{ public function __construct( private ApiKeyRepositoryInterface $repository, private ApiKeyGenerator $generator, private LoggerInterface $logger, ) {}
public function authenticate(string $rawKey): TenantContext {}
public function requireScope(TenantContext $context, ApiKeyScope $requiredScope): void {}}final class QuotaChecker{ public function __construct( private readonly UsageMeterInterface $usageMeter, private readonly LoggerInterface $logger, private readonly Closure $quotaAlertCallback, ) {}
/** @return array{allowed: bool, warning_percentage: float|null} */ public function check(TenantContext $tenant, TenantQuota $quota): array {}}interface UsageMeterInterface{ /** @return array<string, mixed> */ public function pullUsage(array $watermarks): array;
public function getCurrentUsage(string $tenantId): float;}final class StripeMeteringSyncer{ public function __construct( private readonly UsageMeterInterface $usageMeter, private readonly StripeAdapterInterface $stripeAdapter, private readonly LoggerInterface $logger, private readonly Closure $dlqCallback, ) {}
/** @return array{watermarks: array<string, int>, sent: int, failed: int} */ public function sync(array $watermarks): array {}}final readonly class SidecarJwtMinter{ public function __construct( private string $secret, private string $issuer = 'nextpdf-enterprise', private string $audience = 'nextpdf-spectrum', private int $ttlSeconds = self::DEFAULT_TTL_SECONDS, ) {}
public function mint(TenantContext $tenant): string {}}Davranış sözleşmesi
“Davranış sözleşmesi” başlıklı bölüm- Kiracı kimliği. Bir kiracı bağlamı değişmezdir: kiracı tanımlayıcısı, çözümleme kaynağı, kapsamlar. Kimlik yalnızca kimliği doğrulanmış bağlamdan çözümlenir (
jwt,mtls,api_key) — asla istemci tarafından sağlanan bir başlıktan veya sorgu parametresinden değil. Tek kiracılı bir dağıtım, tam kapsamlara sahip sabitdefaultbağlamını kullanır. - Kimlik doğrulama sırası. API anahtarı kimlik doğrulaması sabit bir sırayla ilerler: sağlama toplamı, SHA-256 karma, depo araması, iptal denetimi, süre denetimi, bağlam çözümleme. Bilinmeyen, iptal edilmiş ve süresi dolmuş anahtarlar üç farklı sonuçtur, hepsi HTTP 401; yetersiz kapsam ise HTTP 403’tür.
- Anahtar gizliliği. Ham anahtar asla saklanmaz veya günlüğe kaydedilmez; yalnızca SHA-256 özeti kalıcılaştırılır ve aranır. Kimlik doğrulayıcı, kendisi bayt bazlı bir sır karşılaştırması yapmaz; sabit zamanlı özet araması, depo uygulamasının sözleşmesidir.
- Kota eşikleri. %80 yumuşak sınırında istek devam eder, uyarı yüzdesi döndürülür ve uyarı geri çağrısı tetiklenir. %100 sert sınırında istek, sıfırlama anını taşıyan
SPEC-QUOTA-001(HTTP 402) ile reddedilir — sonraki ayın ilk günü, gece yarısı UTC. - Kota fail-closed. Belirlenemez kullanım, isteği
SPEC-QUOTA-503(HTTP 503, yeniden denenebilir) ile reddeder. Bilinmeyen kullanım asla sıfır olarak değerlendirilmez. Gerçek, ayrıştırılabilir bir sıfır kullanım yetkilidir ve kabul eder. - Uyarı yineleme giderme. Denetleyici uyarıları yineleme gidermez; dönem başına yineleme giderme, geri çağrının sorumluluğudur.
- Ölçümleme eşitleme. Döngü zamanlanmıştır, asla istek yolunda değildir. Kaynak başına imleçlerden devam eder ve her imleci başarıyla gönderilen en yüksek olay kimliğine ilerletir. İdempotensi anahtarı belirlenimcidir — kiracı, dönem, olay kimliği — böylece yeniden gönderilen bir olay, sağlayıcının yineleme gidermesinde birleşir.
- Çekme başarısızlığı. Başarısız bir çekme, imleçleri koruyan işlemsiz bir döngü (
sent0,failed0) döndürür; sonraki döngü, pencereyi atlamak yerine aynı pencereyi yeniden dener. - Hizmet token’ları. Token’lar, paylaşılan bir sırla HS256’dır ve
iss,aud,sub,scope,tenant_id,iat,expile benzersiz birjtitaşır. Varsayılan ömür beş dakikadır. Yapım, 16 bayttan küçük bir sırrı fail-closed olarak reddeder.
Uç durumlar ve başarısızlık modları
“Uç durumlar ve başarısızlık modları” başlıklı bölüm- Hatalı biçimli bir anahtar sağlama toplamında başarısız olur ve herhangi bir veri deposu erişiminden önce reddedilir. İyi biçimli ama bilinmeyen bir anahtar, aramadan sonra reddedilir. Her ikisi de geçersiz-anahtar sonucu olarak ortaya çıkar.
- Bilinmeyen, iptal edilmiş ve süresi dolmuş anahtarlar farklı istisna fabrikaları kullanır;
keyExpiredbayrağı yalnızca süresi-dolmuş sonucunda true’dur. Bunları farklı istemci yanıtlarına eşleyin. QuotaChecker::check()yalnızca kabulde döner; döndürülenallowedher zamantrue’dur. Reddetme ve kullanılamama, istisnai sonuçlardır.TenantQuota::usagePercentage(), pozitif olmayan bir kota için0.0döndürür;fromConfig(), eksik değerler için varsayılanları koyar ve tam sayı limitlerini en az 1’e sıkıştırır.- İmleçler kaynak başınadır; eksik bir imleç, o kaynağın akışının başından (imleç
0) başlar. Çok kaynaklı bir dağıtım, bağımsız imleçler tutar. - Dönüşüm; dizi olmayan olayları, eksik veya boş bir işleme ya da kiracıya sahip olayları, pozitif olmayan bir değere sahip olayları veya eşlenmemiş bir işleme sahip olayları — döngüyü başarısız kılmadan — atlar. Kullanılabilir bir pozitif tam sayı kimliğinden yoksun bir olay, bir uyarıyla reddedilir: rastgele bir yedek anahtar, sağlayıcı tarafındaki yineleme gidermeyi bozar ve kiracıyı iki kez faturalandırabilir.
- Ardışık on gönderme başarısızlığı, kritik bir günlük kaydına yükselir; sayaç, herhangi bir başarılı göndermede sıfırlanır. Her başarısız olay yine de ölü-mektup geri çağrısına ulaşır.
- Bir kullanım-kaynağı ana makinesinden gelen hatalı biçimli bir JSON gövdesi, bir döngü başarısızlığı değil, boş bir olay listesi verir.
pullUsage()yalnızca yapılandırılmış her ana makine erişilemez olduğunda fırlatır.
FIPS modu davranışı
“FIPS modu davranışı” başlıklı bölüm- Özet ve MAC ilkelleri, ana makine PHP kripto sağlayıcısı üzerinden SHA-256 ve HMAC-SHA256’dır. FIPS kısıtlamalı bir derleme, düşürmek yerine onaylanmamış bir algoritmada fail-closed olur; SaaS katmanı kendine ait hiçbir kriptografik politika eklemez.
- Anahtar gövdeleri ve token tanımlayıcıları CSPRNG’den (
random_int(),random_bytes()) gelir. - CRC32 sağlama toplamı bir kriptografik denetim değildir ve FIPS modundan etkilenmez.
Uygunluk
“Uygunluk” başlıklı bölümAşağıdaki ifadeler, yeteneği atıf yapılan maddelere göre açıklar. Bunlar sertifikasyon iddiaları değildir; NextPDF bu modül için hiçbir sertifikasyona sahip değildir.
| Davranış | Referans |
|---|---|
Hizmet-token exp son-tarih anlambilimi | RFC 7519 §4.1.4 |
| Hizmet-token JWS kompakt serileştirmesi | RFC 7515 §3.1 |
| 16 baytlık HS256 sır tabanı; MAC anahtarı olarak insan-hatırlanabilir parola yok | RFC 8725 §3.5 (tehdit: §2.2) |
| Depo özet-araması sabit-zaman sözleşmesi | OWASP ASVS 5.0 §11.2.4 |
| API anahtarı depolama özeti SHA-256 | FIPS 180-4 (kodda bildirilmiş) |
RFC 8725 ve OWASP ASVS 5.0 atıfları RAG-doğrulanmıştır; tam referans tanımlayıcıları bu sayfanın frontmatter’ında kayıtlıdır. FIPS 180-4, FIPS 198-1 ve BSI TR-02102-1 referansları ürün kaynağında kodda bildirilmiştir (hash('sha256', …) ve üretecin belgelenmiş anahtar tabanı); bunlar bu sayfa için RAG bütüncesinden alınmamıştır. ASVS §11.2.4’ün sabit-zaman gereksinimi, kimlik doğrulayıcı sınıfının kendisini değil, operatörün sağladığı depo uygulamasını bağlar.
Geliştirme notları
“Geliştirme notları” başlıklı bölümApiKeyRepositoryInterfaceveStripeAdapterInterfaceiçin kalıcı uygulamalar sağlayın; paket, kalıcılığı değil, sözleşmeleri ve bir PSR-18 sağlayıcı istemcisini sevk eder.- Bağımlılıklar yalnızca PSR soyutlamalarıdır: PSR-3 logger, PSR-18 HTTP istemcisi, PSR-17 istek ve akış fabrikaları. Hiçbir sağlayıcı SDK’sı gerekmez.
- Ölçümleme eşitlemesini zamanlanmış bir iş olarak çalıştırın. Döndürülen imleçleri her döngüden sonra kalıcı olarak saklayın.
- Kota uyarı yüzdesini istemcilere gösterin, örneğin bir uyarı başlığı olarak, ve kota uyarılarını geri çağrıda dönem başına yineleme giderin.
- Token-üreteci sırrını yapılandırmadan yüksek-entropili rastgele bir değer olarak sağlayın; 32 veya daha fazla rastgele bayt önerilir. Bunu asla bir paroladan türetmeyin.
- Anahtar önekleri, ortamı bir arama olmadan görünür kılar; sandbox ve production anahtarları asla çakışmaz çünkü önek, saklanan özete katılır.
- Dahilî mekanizma ayrıntısı, kaynak deposunun dahilî belgelerinde kalır ve bu kılavuzun kapsamı dışındadır.
Yayın sınırı
“Yayın sınırı” başlıklı bölümBu sayfa yalnızca dışarıdan gözlemlenebilir davranışı ve desteklenen genel API yüzeyini belgeler. Dahilî ad alanı yolları, yardımcı sınıflar, mekanizma tabloları, runbook dosya adları ve bilet önekleri kapsam dışıdır.