Jelvényellenőrzés beágyazása a weboldaladra (iframe és SDK nélkül)

Adj a weboldaladhoz egy kis JavaScript-részletet (vagy szerveroldali fetch-et), amely nyilvános JSON-LD végponton ellenőrzi bármelyik Open Badge-et. Nincs iframe, nincs harmadik féltől származó követő.

Nacho Coll Szerző: Frissítve 9 perc olvasás
Adj a weboldaladhoz egy kis JavaScript-részletet (vagy szerveroldali fetch-et), amely nyilvános JSON-LD végponton ellenőrzi bármelyik Open Badge-et. Nincs iframe, nincs harmadik féltől származó követő.

Ha kiállítasz tanúsítványokat, előbb-utóbb valaki megkérdezi: „Honnan tudom, hogy ez a jelvény valódi?” Az őszinte válasz soha nem lehet az, hogy „bízz a PNG-ben”. Az Open Badge v2.0 erre egy nyilvános, géppel olvasható ellenőrzési végpontot ad, és egy „Ellenőrzött” widget a saját oldaladon nagyjából tíz sornyi kód — nem iframe, nem harmadik féltől származó beágyazó szkript, és nem SDK.

Ez a bejegyzés pontosan megmutatja, hogyan hívd meg a végpontot és hogyan jelenítsd meg az eredményt, sima JavaScriptben, valamint szerveroldalon Node-ban és Pythonban. Kitér arra is, mit ellenőriz valójában az „ellenőrzés”, hol a helye a végpontnak a badges.ninja által a kedvezményezetteknek már most biztosított, emberi olvasásra szánt oldalak mellett, és milyen hibák miatt tűnik késznek egy ellenőrző widget, miközben csendben semmit sem bizonyít.

Mit jelent valójában az „ellenőrzött”

Az Open Badge v2.0 assertion egy rögzített szerkezetű JSON-LD dokumentum: maga az assertion (ki kapta, mikor), egy hivatkozás a BadgeClassra (mi ez, ki határozza meg a feltételeket) és egy hivatkozás a kibocsátó profiljára (ki áll jót érte). Amikor „ellenőrzöl” egy jelvényt, valójában három külön dolgot vizsgálsz:

  1. Létezik-e az assertion, és feloldható-e. A díj azonosítója valódi, nem kitalált vagy meghamisított.
  2. Visszavonták-e. A kibocsátó utólag visszavonhat egy jelvényt — tévesen kiállított tanúsítvány, szabálysértés, lejárt minősítés miatt —, és a helyes ellenőrzőnek ezt jeleznie kell, nem elég megerősítenie, hogy a rekord létezik.
  3. Összeáll-e a lánc. Az assertion jelvény- és kibocsátó-hivatkozásai valódi, egymáshoz illő rekordokra mutatnak, nem árva vagy eltérő azonosítókra.

Az a widget, amely csak lekér egy URL-t, és a 200 státuszt nézi, a 2. pontot teljesen elvéti. Egy visszavont assertion továbbra is hibátlanul feloldódik — csak a tartalmában ott a visszavonási jelző. Ha a widgeted csak azt vizsgálja, „sikerült-e a kérés”, a visszavont tanúsítvány ellenőrzöttként jelenik meg, ami rosszabb, mintha egyáltalán nem lenne widget.

A nyilvános emberi oldal és az API-végpont

A https://badges.ninja oldalon kiadott minden díj kap egy nyilvános URL-t, amelyet a kedvezményezettek közvetlenül megoszthatnak, megtekintéséhez nem kell regisztrálni:

Public credential page

A legtöbb kedvezményezett erre az oldalra linkel majd LinkedInről, önéletrajzból vagy e-mail-aláírásból — emberekre van szabva, megmutatja a jelvény képét, a kibocsátót és a kiállítás dátumát, és semmit nem kell tenned azért, hogy működjön. Az alábbi API-végpont ugyanazt az assertiont adja vissza strukturált JSON-LD-ként, és erre van szükséged, ha saját felületet építesz ahelyett, hogy csak a miénkre mutatnál.

A végpont

GET https://api.badges.ninja/certify-badge/award/{guid}

Nem kell hitelesítési fejléc — ez szándékosan nyilvános, hiszen az Open Badges lényege, hogy bárki (munkáltató, toborzó, engedélyező testület) fiók nélkül ellenőrizhessen egy tanúsítványt. A teljes szerződés, beleértve a visszaadott assertion pontos mezőneveit, az ellenőrzési dokumentációban található.

A díj GUID-ját add át; ezt vagy a saját kiállítási nyilvántartásodból ismered, vagy egy kedvezményezett által megosztott badges.ninja/awards/<guid> linkből nyered ki.

Sima JS: lekérés és megjelenítés

Ez a teljes widget. Nincs build lépés, nincs npm-csomag, bármelyik oldalra beillesztheted:

<div id="badge-verify"></div>
<script>
  async function renderBadgeVerification(awardId, mountId) {
    const el = document.getElementById(mountId);
    el.textContent = "Checking badge status";
    try {
      const res = await fetch(
        `https://api.badges.ninja/certify-badge/award/${awardId}`
      );
      if (!res.ok) {
        el.textContent = "Credential not found.";
        return;
      }
      const assertion = await res.json();
      // —— revocation check first, a resolvable assertion isn't enough on its own
      if (assertion.revoked) {
        el.textContent = `Revoked: ${assertion.revocationReason || "no reason given"}`;
        return;
      }
      el.textContent = `Verified, issued ${new Date(assertion.issuedOn).toLocaleDateString()}`;
    } catch (err) {
      el.textContent = "Verification check failed.";
    }
  }
  renderBadgeVerification("REPLACE_WITH_AWARD_ID", "badge-verify");
</script>

Cseréld a REPLACE_WITH_AWARD_ID értéket egy valódi díj-GUID-ra. Ez a teljes kliensoldali integráció: nincs iframe-határ, amellyel a CSS-sel hadakoznod kellene, és nincs harmadik féltől származó szkript, amely az ellenőrzés mellé saját analitikát vagy követőpixeleket hozna.

Szerveroldalon: Node

Ha inkább a backenden ellenőriznél — például mielőtt egy „Ellenőrzött partner” jelvényt jelenítesz meg egy általad kezelt profiloldalon, vagy mielőtt egy onboarding folyamatban elfogadsz egy tanúsítványt igazolásként —, a lekérés ugyanaz, csak a DOM-os rész marad el:

async function verifyAward(awardId) {
  const res = await fetch(
    `https://api.badges.ninja/certify-badge/award/${awardId}`
  );
  if (!res.ok) return { verified: false, reason: "not_found" };
  const assertion = await res.json();
  if (assertion.revoked) {
    return { verified: false, reason: assertion.revocationReason || "revoked" };
  }
  return { verified: true, issuedOn: assertion.issuedOn, badge: assertion.badge };
}

Szerveroldalon: Python

import requests
# —— resolve the assertion, then check revocation before trusting it
def verify_award(award_id):
    res = requests.get(f"https://api.badges.ninja/certify-badge/award/{award_id}")
    if res.status_code != 200:
        return {"verified": False, "reason": "not_found"}
    assertion = res.json()
    if assertion.get("revoked"):
        return {"verified": False, "reason": assertion.get("revocationReason", "revoked")}
    return {"verified": True, "issued_on": assertion.get("issuedOn"), "badge": assertion.get("badge")}

Mindkét példa a nem 200-as választ „nem található”-ként kezeli, ahelyett hogy kivételt dobna. Egy hibás vagy kitalált díjazonosító egy nyilvános ellenőrző végpontnál várt bemenet, nem kivételes eset, ezért kezeld normál ágként, ne elkapott hibaként.

Az eredmény stílusozása, ahelyett hogy valaki más felületét ágyaznád be

Mivel a fenti widget csak egy fetch hívás a saját DOM-odba, minden pixel a tiéd. Gyakori minta három vizuális állapot, közvetlenül a válaszból leképezve:

  • Ellenőrzött — zöld pipa, az „Ellenőrzött” felirat és a kiállítás dátuma, az oldalad jelvény-/címkekomponenseihez igazítva.
  • Visszavonva — tompított vagy piros állapot, amely megmutatja a visszavonás okát, nem elrejti. A kedvezményezettek és a harmadik felek is jobban járnak egy őszinte „miért”-tel, mint egy néma hibával.
  • Nem található — vizuálisan kezeld úgy, mint a „visszavont” esetet (ne jeleníts meg hamis sikerállapotot), de más szöveggel, mert egy hibás azonosító és egy szándékos visszavonás más helyzet annak, aki az oldalt olvassa.

Mindehhez nem kell komponenskönyvtár. Egy switch a verified / revoked / not_found értékeken és három CSS-osztály elég.

Gyorsítótárazás, hogy ne terheld a végpontot

Az ellenőrző végpont nyilvános és hitelesítés nélküli, ami azt is jelenti, hogy kérésenként nincs kreditköltség — de ha kliensoldalról, gyorsítótár nélkül hívod, minden oldalbetöltésnél hálózati körút. Egy olyan oldalon, amely minden látogatónak ugyanazt a jelvényt mutatja (például egy „Ellenőrzött partner” lábléces jelvény), szerveroldalon tárold az eredményt rövid TTL-lel — öt-tizenöt perc bőven elég, mert a visszavonások nem gyorsan változó jelzések —, ahelyett hogy minden kérésnél újra lekérnéd:

const cache = new Map();
async function verifyAwardCached(awardId, ttlMs = 10 * 60 * 1000) {
  const hit = cache.get(awardId);
  if (hit && Date.now() - hit.at < ttlMs) return hit.result;
  const result = await verifyAward(awardId);
  cache.set(awardId, { result, at: Date.now() });
  return result;
}

Látogatónkénti widgetnél (amikor egy kedvezményezett a saját tanúsítványát ágyazza be egy személyes oldalra) hagyd ki a gyorsítótárat, és hívd frissen az oldalbetöltéskor — ekkora léptéknél a plusz kérés elhanyagolható.

Mit ad a badges.ninja már most a kedvezményezetteknek

Mielőtt teljesen egyedi beágyazást építenél, érdemes tudni, mi áll rendelkezésre készen. Minden díj nyilvános oldala kész megosztó és beágyazó kódrészleteket tartalmaz, amelyeket a kedvezményezettek közvetlenül másolhatnak, kód nélkül:

Public share page with social buttons + embed snippets

Ha a célod az, hogy „a kedvezményezett megmutathassa, hogy a jelvénye valódi”, a badges.ninja/awards/<guid> oldalára linkelni gyakran egyszerűbb, mint egyedi widgetet építeni — ez a korábban bemutatott emberi oldal, és az ellenőrzött/visszavont különbséget már kezeli helyetted. A bejegyzés egyedi widgetjét akkor építsd meg, ha az ellenőrzési állapotot a saját terméked felületén belül kell megjeleníteni — partnerkönyvtárban, belső audit-irányítópulton, vagy egy olyan toborzóeszközben, amely a jelölt állított minősítéseit ellenőrzi —, ahol egy másik oldalra átirányítani nem megfelelő felhasználói élmény.

Miért nem iframe vagy szállítói widget?

Egyes platformok az ellenőrzési állapot beágyazásához egy ilyen részletet adnak: <iframe src="https://vendor.example.com/verify-widget">. Működik, de valódi költségei vannak: a tartalmat nem tudod az oldalad stílusához igazítani (a szállító CSS-ével maradsz), egy cross-origin dokumentumot vezet be, amelyet a Content-Security-Policy-nek kifejezetten engedélyeznie kell, és minden oldalbetöltés kérést indít egy harmadik fél iframe-kiszolgálója felé, akkor is, ha a látogatót az ellenőrzési állapot egyáltalán nem érdekli. A két hívásos fetch widget mindhármat elkerüli — a te DOM-od, a te stílusod, és csak akkor fut, amikor te úgy döntesz.

A teljes ellenőrzési lánc bejárása

Ha a státusz-widgetnél alaposabbat építesz — például egy audit eszközt, amely tanúsítványok egy csoportját ellenőrzi, vagy megfelelőségi jelentést —, járd be a teljes láncot, ne állj meg az assertionnél. Az assertion egy badge URL-re hivatkozik (a BadgeClass: név, leírás, feltételek), a BadgeClass pedig egy issuer URL-re (a szervezet profilja). Egy szigorú ellenőrző mindhármat feloldja, és megerősíti, hogy belsőleg konzisztensek — a jelvény tényleg ahhoz a kibocsátóhoz tartozik, amelyet állít, az assertion tényleg arra a jelvényre hivatkozik, amelyet állít —, nem csak azt, hogy a legfelső szintű assertion 200-at ad. Ez több mélység, mint amennyit egy egyetlen tanúsítványt mutató widget igényel, de jó tudni, hogy létezik, ha egy partner vagy auditor valaha megkérdezi: „milyen mélyen ellenőriztek valójában?”

Kerülendő gyakori hibák

  • Csak a HTTP-státusz ellenőrzése. Ahogy fentebb szó volt róla, a visszavont assertion továbbra is feloldódik. Mindig olvasd az assertion.revoked mezőt, ne csak a státuszkódból következtess az ellenőrzöttségre.
  • A díjazonosító beégetése egy megosztott komponensbe. Ha a widget több kedvezményezett oldalán újrahasználható, a díjazonosítót paraméterként vedd át (data-attribútum, query string, prop), ne a szkriptbe égetett literálként.
  • A hálózati hibák csendes elnyelése. Egy try/catch, amely semmit sem naplóz, és ugyanazt a „nem található” szöveget mutatja, mint egy valóban hiányzó jelvénynél, később nehézzé teszi a hibakeresést. Különítsd el a „a hálózati hívás meghiúsult” és az „az API nemet mondott” esetet a hibaágakban, legalább a naplókban.
  • Újraellenőrzés minden renderelésnél egy kliensoldali alkalmazásban. Ha a widget egy gyakran újrarenderelő React- vagy Vue-komponensben él, csatolásonként egyszer (vagy a gyorsítótár TTL-ablakonként egyszer, a gyorsítótárazásról szóló szakasz szerint) ellenőrizz, ne minden újrarenderelésnél.

Kerül-e krédibe, és működik-e az ingyenes csomagon?

Nem. Az ellenőrző végpont szándékosan kívül esik a kiállítást szabályozó kreditrendszeren — annak ellenőrzése, hogy egy jelvény érvényes-e, nem kerül semmibe a kibocsátónak, és a hívó látogatónak sem kell fiók, API-kulcs vagy bármilyen csomag. Ez attól függetlenül igaz, hogy a jelvényt Free, Starter vagy Pro csomagon állították ki: az ellenőrzés magának a tanúsítványnak a tulajdonsága, nem a kibocsátó előfizetéséhez kötött funkció. Ezért tehetsz biztonságosan ilyen widgetet nyilvános, kiszámíthatatlan forgalmú oldalra (karrieroldal, partnerkönyvtár) anélkül, hogy a fiókodhoz kötött sebességkorlátoktól kellene tartanod — egy csak olvasható, nyilvános végpontot hívsz, nem hitelesített API-útvonalat.

Egy dolgot érdemes kimondani: a végpont által visszaadott assertion JSON nem tartalmazza a kedvezményezett nyers e-mail-címét. A kedvezményezett e-mailje hashelve van tárolva a backenden, éppen azért, hogy egy nyilvános ellenőrzési válaszból ne lehessen személyes elérhetőségeket kinyerni — amit visszakapsz, az elég a tanúsítvány megerősítéséhez (jelvény, kibocsátó, dátumok, visszavonási állapot), anélkül hogy a végpont leadgeneráló eszközzé válna bárkinek, aki végigpörgeti a díjazonosítókat.

Készen állsz az első ellenőrizhető tanúsítványod kiállítására?

Kezdd ingyen a badges.ninja-n — vizuális tervező, nyilvános ellenőrzőoldal, PDF-tanúsítvány, Open Badge v2.0 kimenet. Bankkártya nem szükséges.

Az assertion minden mezőjének teljes, kommentált szerkezetéhez lásd a JSON-LD mezőreferenciát. Ha pedig programozottan állítasz ki tanúsítványokat, nem csak ellenőrzöd őket, az API gyorsindító bemutatja a hitelesítést és a díjlétrehozó hívást, amelyből ennek a végpontnak a kimenete származik.

Nacho Coll

A szerzőről

Founder & Engineer at Badges Ninja

Nacho founded Badges Ninja to make issuing verifiable digital credentials as simple as a single API call — Open Badge v2.0 badges and certificates, minted, hosted, and verifiable without standing up your own issuer infrastructure. Writes about the Open Badges spec, credential verification, and running a credentialing platform serverless on AWS, from the operator side of the wire.

Vissza a Blogra

Kapcsolódó cikkek