LU08.A03 - Bookshelf mit Authentifikation mit Bruno

Erweitere deine Bruno-Requests um Authentifikation, Autorisation und automatisierte Tests – nach Bruno-Best-Practices.

Zielbild

Ausgangslage

Erweiterte API: https://it.bzz.ch/book/ext/ (Login/Token, Rollen)

Rolle Benutzername Passwort Berechtigung
admin admin admin alle Funktionen
user musterh geheim read, list
guest nur login

Ohne gültiges Token → Rolle guest → nur login. Fehlende Berechtigung → 403.

Projektstruktur (Beispiel)

bookshelf-bruno/
  auth/
    login-admin.bru
    login-user.bru
    login-invalid.bru
  books/
    read-book.bru
    list-books.bru
    save-book.bru     (optional)
    delete-book.bru   (optional)
  environments/
    dev.json
    dev.local.json      (in .gitignore!)

Hinweise

Environments

environments/dev.json

{
  "name": "dev",
  "vars": {
    "baseUrl": "https://it.bzz.ch/book/ext"
  }
}

environments/dev.local.json (nicht einchecken)

{
  "name": "dev.local",
  "vars": {
    "token": "",
    "username": "admin",
    "password": "admin"
  }
}
Aktiviere zuerst dev, dann zusätzlich dev.local (oder führe beide Inhalte zu einem aktiven Environment zusammen – Hauptsache: token lebt lokal).

Requests (auth)

login-admin.bru

POST → {{baseUrl}}/login Body (JSON): {„username“:„admin“,„password“:„admin“}

Tests

test("Login admin -> 200 & token gesetzt", () => {
  expect(res.status).to.equal(200);
  const data = res.json();
  expect(data).to.have.property("token");
  // Token nur im aktiven (lokalen) Environment halten:
  bru.setEnvVar("token", data.token, { persist: false });
});

login-user.bru

POST → {{baseUrl}}/login Body (JSON): {„username“:„musterh“,„password“:„geheim“}

Tests

test("Login user -> 200 & token gesetzt", () => {
  expect(res.status).to.equal(200);
  const data = res.json();
  bru.setEnvVar("token", data.token, { persist: false });
});

login-invalid.bru

POST → {{baseUrl}}/login Body (JSON): {„username“:„wrong“,„password“:„wrong“}

Tests

test("Login invalid -> 401, kein token", () => {
  expect(res.status).to.equal(401);
});

Requests (books)

Gemeinsame Header: im Request Headers

read-book.bru

GET → {{baseUrl}}/read/<book_uuid>

Tests (rollenbewusst, aber ohne Ablaufsteuerung)

test("Read Book – rollenabhängig", () => {
  const s = res.status;
  if (bru.getVar("token")) {
    // Angemeldet: admin/user
    expect(s).to.equal(200);
    const b = res.json();
    expect(b).to.have.property("book_uuid");
    expect(b).to.have.property("title");
  } else {
    // guest (ohne Token)
    expect(s).to.equal(403);
  }
});

list-books.bru

GET → {{baseUrl}}/list

Tests

test("List Books – rollenabhängig", () => {
  const s = res.status;
  if (bru.getVar("token")) {
    expect(s).to.equal(200);
    const arr = res.json();
    expect(Array.isArray(arr)).to.equal(true);
    // ggf. bekannte Länge/Felder prüfen
  } else {
    expect(s).to.equal(403);
  }
});

Ausführung (Runner ohne Script-Steuerlogik)

Variante 1 (empfohlen & simpel): drei Läufe mit klaren Vorbedingungen

1. ''guest'': ''token'' in ''dev.local.json'' leer lassen → ''list-books'', ''read-book'' ausführen → **403** erwartet.  
2. ''user'': ''login-user.bru'' einmal senden → ''token'' wird gesetzt → ''list/read'' → **200**.  
3. ''admin'': ''login-admin.bru'' einmal senden → ''list/read'' → **200** (volle Rechte).

Variante 2 (Runner-Ordnung):

Best Practice: Keine Ablaufsteuerung per Script (setNextRequest). Halte Tests kurz & deterministisch; die Reihenfolge steuert der Runner/Ordner.

Qualitäts-Checks (Best Practices)

Abgabe

Packe dein Bruno-Projekt (Ordner mit allen .bru-Dateien und den nicht-sensiblen Environments) als ZIP und lade die ZIP-Datei in Moodle hoch. Nicht einchecken/abgeben: Dateien mit Token/Passwörtern (z. B. dev.local.json).


Kevin Maurizi