Dokümanlar menüsü
Kullanıcı yönetimi (journal-destekli)
Bearer token → Principal doğrulayan, journal'da token'ı HASH'li saklayan kullanıcı deposu; Studio 'Kullanıcılar' görünümünden ekle/sil, token yalnız oluşturmada bir kez gösterilir.
Ne işe yarar / ne zaman kullanılır#
Açık-çekirdek roleAuth sabit kod içinde tanımlı birkaç token'la çalışır — yeni bir kullanıcı eklemek için deploy gerekir. createJournalUserStore bunun yerine kullanıcıları journal'da tutar (policy/budget'ta olduğu gibi veri-güdümlü): operatör Studio'dan yeni bir kullanıcı oluşturur, dönen token o kişiye verilir, kullanıcı o token'la Authorization: Bearer <token> ile istek atar — deploy'suz, kod değişikliği olmadan.
Somut senaryo: bir SaaS dağıtımında operatör (organizasyonsuz admin) her yeni müşteri organizasyonu için Studio "Kullanıcılar" görünümünden bir üye oluşturur (organizasyon ataması ile), token'ı müşteriye iletir; müşteri o token'la kendi organizasyonuna kapsanmış şekilde API'yi kullanır. Organizasyon-admin ise yalnız kendi organizasyonunun üyelerini yönetebilir.
Kurulum / import#
import { createEnterpriseAuth, createJournalUserStore, createJournalAuditSink } from '@gnldev/auth-ee';
import { toJournal } from '@gnldev/durable';
import { SqliteStorage } from '@gnldev/durable/sqlite';@gnldev/auth-ee paralı/lisanslı bir pakettir. createJournalUserStore, listKeys, putIfAbsent ve putIfMatch destekleyen bir journal ister — son ikisi eşzamanlı isteklerde koltuk sayısını ve e-posta tekilliğini doğru tutar; toJournal(storage) buna uyar (birinci taraf journal'ların hepsinde üçü de var). createPostgresUserStore(pool) aynı dizini kendi tablolarında tutar ve aynı şekilde cevap verir.
Adım adım kullanım#
1. Depoyu journal üzerinde kurun ve createEnterpriseAuth'a userStore olarak verin — SSO'dan sonra, açık-çekirdek fallback'ten önce devreye girer:
const userStore = createJournalUserStore(toJournal(storage));
const auth = createEnterpriseAuth({
licenseKey,
failClosed: true,
userStore,
audit: createJournalAuditSink(toJournal(storage)),
fallback: roleAuth({
admin: { token: ADMIN_TOKEN, user: 'ops' }, // bootstrap operator
}),
});2. Aynı userStore'u Studio'ya users seçeneğiyle verin — bu, Studio'da "Kullanıcılar" görünümünü ve /users uçlarını açar:
app.mount('/studio', createStudioApp({
reader: toJournal(storage),
gnl,
auth,
users: userStore, // the Studio "Users" view — add/remove; the token is shown once
userErasure: { storage }, // DELETE /users/:id also erases the person's data; without it → 409
}));3. Studio'dan (veya userStore.create() ile programatik) yeni kullanıcı oluşturunca dönen token yalnız o an gösterilir — sunucu düz token'ı hiçbir yerde saklamaz, yalnız SHA-256 hash'ini journal'a yazar. Kullanıcının id'si asla e-posta değildir: her kullanıcı rastgele bir id (usr_…) alır, e-posta ayrı ve tekil bir alandır. Koşumlar ve thread'ler sahip olarak bu id'yi kaydeder; aynı e-postayla gelen bir sonraki kişiye aynı id verilseydi önceki kişinin verisi ona geçerdi. Bundan önce yazılmış kayıtlar e-posta biçimli id'lerini korur:
const { user, token } = await userStore.create({
email: '[email protected]',
roles: ['viewer'],
orgId: 'acme',
ttlMs: 30 * 24 * 60 * 60 * 1000, // expires automatically after 30 days
});
// token: 'eeu_...' — returned HERE ONLY; if it is lost, userStore.revoke() then create() again4. Kullanıcı o token'ı Authorization: Bearer eeu_... başlığıyla gönderir; authenticate() token'ın SHA-256'sını journal'daki ters indekste arar, süresi dolmuş (expiresAt) veya iptal edilmiş (revoked) değilse bir Principal döner ve lastUsedAt'i best-effort günceller.
Kullanıcıyı silmeden erişimini kesmek için userStore.revoke(id) kullanılır — kayıt (audit/geçmiş için) kalır, yalnız token ters indeksi kaldırılır ve revoked: true işaretlenir. İptal edilen kullanıcı koltuğunu boşaltır.
Koltuk sayısı lisanstan gelir. createEnterpriseAuth, lisanstaki seats'i verdiğiniz userStore'a bağlar; depo bu sayıyı kendi verisine yazar (journal'da __eelicence__:seats, Postgres'te gnl_ee_licence tablosu). Aynı veri üzerindeki her depo bunu create'te uygular — Studio'ya verilen ikinci bir depo nesnesi ya da başka bir süreçte kurulan depo lisansı aşamaz. Koltuk atomik olarak alınan bir yuvadır; iki eşzamanlı istek son koltuğu birlikte alamaz. Sınır aşılınca create SeatsExceededError fırlatır. Deponun kendi seats seçeneği lisanstan düşük olabilir (kendi tavanınız); yüksek olanı boot'ta reddedilir.
Studio'da silmek, yalnız dizin kaydını değil kişiyi siler. DELETE /users/:id token'ı iptal eder, kişinin koşumlarını, thread'lerini, hafızasını ve dokümanlarını @gnldev/durable'ın eraseSubject'i ile siler, sonra kaydı kaldırır — bu yüzden Studio'ya userErasure verilmelidir (ajanlarınızın çalıştığı storage, isteğe bağlı erasers ve memory). Verilmezse silme 409 ile reddedilir: bunun yerine kullanıcıyı iptal edin ya da veriyi bilerek tutuyorsanız (yasal saklama, başka yerde yürüttüğünüz bir silme) ?keepData=true ile silin. Çalışmakta olan bir tur beklenir, en fazla userErasure.settleMs kadar (varsayılan 10 000 ms); süre dolduğunda hâlâ yazan koşumlar iptal edilir ve silme hiçbir şey silmeden 409 user_runs_in_flight döner — kullanıcı listede, iptal edilmiş olarak kalır; aynı silme tekrar gönderilince tamamlanır. Tek başına userStore.remove(id) yalnızca dizin kaydını (kayıt, token, koltuk, e-posta) kaldırır.
API referansı#
createJournalUserStore(journal: JournalLike, opts?: { seats? }) => JournalUserStore. journal listKeys, putIfAbsent ve putIfMatch desteklemeli, yoksa fırlatır. seats kendi tavanınızdır, lisanstakini aşamaz.
JournalUserStoreauthenticate(token, now?), list(), create(input), update(id, patch), remove(id), revoke(id), seats, bindLicenceSeats(seats) sözleşmesi. create() { user, token } döner ve koltuk sınırında SeatsExceededError fırlatır; remove() yalnızca dizin kaydını siler.
EeUserRecordJournal'da saklanan tam kayıt: id (usr_…), email?, name?, roles, kind?, orgId?, permissions?, tokenHash, createdAt, expiresAt?, lastUsedAt?, revoked?, seat?.
EeUserPublicEeUserRecord eksi tokenHash ve seat; kind her zaman çözülmüş olarak (eksik kind subject okunur) — list() ve Studio'ya açılan güvenli görünüm.
CreateUserInputcreate() girdisi: email?, name?, roles?, permissions?, orgId?, kind? (varsayılan subject), ttlMs? (öncelikli), expiresAt?.
StudioAppOptions.userscreateStudioApp'e verilen StudioUserStore — verilirse Studio 'Kullanıcılar' görünümü + /users uçları açılır.
StudioAppOptions.userErasure{ storage, erasers?, memory?, settleMs? } — Studio'nun DELETE /users/:id ucunun kişinin verisini kayıtla birlikte silmesini sağlar. Verilmezse silme 409 döner (?keepData=true hariç).
@gnldev/auth-ee paralı/lisanslıdır. Verilmiş ama geçersiz bir licenseKey varsayılan olarak boot'u durdurur; anahtar yoksa ya da failClosed: false ise createEnterpriseAuth fallback'e düşer ve userStore devreye girmez. features listesinde users olmayan bir lisans, userStore'u girişte uyarıyla yok sayar (failClosed: true ile boot hatası olur).'admin' (yazma) ya da 'viewer' (okuma) olur ve bir organizasyona kapsanır. Gözden kaçması kolay iki tane daha var — 'member' ikisinin arasında durur (okuma artı agents:run, yani biri admin olmadan ajan koşturabilir) ve ayrılmış 'platform-admin' organizasyonlar-arası açık yetkidir. Sonuncusu olmadan organizasyonsuz bir kullanıcı fail-closed'dır, yani kimse bir orgId unutarak süper admin olmaz. Ayrı bir permissions[] verdiğinizde rolün yetkilerini tümden ezer — altı adlandırılmış okuma izni kişi başına böyle atanır.