Уградите верификацију беџева на свој сајт (без iframe-а, без SDK-а)

Додајте на свој сајт мали JavaScript исечак (или серверски fetch) који верификује било који Open Badge преко јавног JSON-LD endpoint-а. Без iframe-а, без трекера трећих страна.

Nacho Coll Аутор Ажурирано 9 мин читања
Додајте на свој сајт мали JavaScript исечак (или серверски fetch) који верификује било који Open Badge преко јавног JSON-LD endpoint-а. Без iframe-а, без трекера трећих страна.

Ако издајете сертификате, пре или касније неко ће питати: „како да знам да је ова значка права?“ Искрен одговор никада не сме да буде „верујте PNG-у“. Open Badge v2.0 то решава јавним, машински читљивим endpoint-ом за верификацију, а постављање видџета „Верификовано“ на ваш сајт захтева десетак линија кода — без iframe-а, без скрипте треће стране и без SDK-а.

Овај текст показује тачно како да позовете endpoint и прикажете резултат, у чистом JavaScript-у и на серверу у Node-у и Python-у. Објашњава и шта „верификација“ заиста проверава, где се endpoint уклапа поред страница за људе које badges.ninja већ нуди примаоцима, и које грешке праве да видџет за верификацију изгледа готов а тихо не доказује ништа.

Шта „верификовано“ заправо значи

Assertion у Open Badge v2.0 је JSON-LD документ фиксне структуре: сам assertion (ко га је добио и када), референца на BadgeClass (шта је и ко одређује критеријуме) и референца на профил издавалаца (ко јемчи за њега). Када „верификујете“ значку, заправо проверавате три одвојене ствари:

  1. Да ли assertion постоји и да ли се разрешава. ID награде је стваран, није погођен нити измењен.
  2. Да ли је опозван. Издавалац може накнадно да опозове значку — сертификат издат грешком, кршење правила, истекла сертификација — и исправан верификатор то мора да прикаже, а не само да потврди да запис постоји.
  3. Да ли ланац држи на окупу. Референце assertion-а на значку и издаваоца заиста воде до стварних, усаглашених записа, а не до напуштених или неусклађених ID-јева.

Видџет који само пингује URL и проверава статус 200 у потпуности промашује тачку 2. Опозван assertion се и даље нормално разрешава — само у садржају носи ознаку опозива. Ако ваш видџет проверава само „да ли је захтев успео“, опозван сертификат ће се приказати као верификован, што је горе него да видџета уопште нема.

Јавна страница за људе наспрам API endpoint-а

Свака награда издата на https://badges.ninja добија јавни URL који примаоци могу директно да деле, без регистрације за преглед:

Public credential page

На ту страницу ће већина прималаца упутити са LinkedIn-а, из биографије или имејл потписа — направљена је за људе, приказује слику значке, издаваоца и датум издавања и не тражи ништа од вас да би радила. Endpoint у наставку враћа исти assertion као структурирани JSON-LD, што вам треба када градите сопствени интерфејс уместо да само упућујете на наш.

Endpoint

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

Није потребан auth header — ово је намерно јавно, јер је цела поента Open Badges-а да свако (послодавац, регрутер, лиценцно тело) може да верификује сертификат без налога. Потпуни детаљи уговора, укључујући тачна имена поља у враћеном assertion-у, налазе се у документацији о верификацији.

Проследите GUID награде, који ћете имати или из сопствених евиденција издавања или издвојен из везе badges.ninja/awards/<guid> коју је с вама поделио прималац.

Чисти JS: fetch и приказ

Ово је цео видџет. Без корака изградње, без npm пакета, једноставно га убаците на било коју страницу:

<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>

Замените REPLACE_WITH_AWARD_ID стварним GUID-ом награде. То је цела интеграција на клијентској страни: нема границе iframe-а са којом бисте се борили преко CSS-а, нити скрипте треће стране која уз проверу доноси сопствену аналитику или пикселе за праћење.

На серверу: Node

Ако радије верификујете на бекенду — рецимо, пре приказа значке „Верификован партнер“ на профилној страници коју контролишете, или пре прихватања сертификата као доказа у процесу увођења — fetch је исти, само без DOM дела:

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 };
}

На серверу: 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")}

Оба примера одговор различит од 200 третирају као „није пронађено“ уместо да бацају грешку. Покварен или погођен ID награде очекиван је улаз за јавни endpoint за верификацију, а не изузетак, зато га обрадите као нормалну грану, а не као ухваћену грешку.

Стилизовање резултата уместо уградње туђег интерфејса

Пошто је видџет изнад само fetch позив у ваш DOM, свака тачка је ваша. Уобичајен образац су три визуелна стања која произилазе директно из одговора:

  • Верификовано — зелена кукица уз „Верификовано“ и датум издавања, стилизована да одговара компонентама значки/ознака на вашем сајту.
  • Опозвано — пригушено или црвено стање које приказује разлог опозива уместо да га крије. И примаоци и трећа лица имају корист од искреног „зашто“, а не од тихе грешке.
  • Није пронађено — визуелно га третирајте као „опозвано“ (не приказујте лажно стање успеха), али са другачијим текстом, јер су погрешан ID и намерни опозив различите ситуације за онога ко чита страницу.

Ништа од овога не захтева библиотеку компоненти. Довољни су један switch по verified / revoked / not_found и три CSS класе.

Кеширање, да не засипате endpoint

Endpoint за верификацију је јаван и без аутентикације, што значи и да нема трошка кредита по захтеву — али је и даље мрежни позив при сваком учитавању странице ако га зовете са клијента без кеширања. За страницу која свим посетиоцима приказује исту значку (на пример значку „Верификован партнер“ у подножју), кеширајте резултат на серверу са кратким TTL-ом — пет до петнаест минута је сасвим довољно, јер опозиви нису сигнал који се брзо мења — уместо да поново преузимате при сваком захтеву:

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;
}

За видџет по посетиоцу (прималац који уграђује сопствени сертификат на лични сајт) прескочите кеш и једноставно га позовите свеже при учитавању странице — додатни захтев је на тој скали занемарљив.

Шта badges.ninja већ даје примаоцима

Пре него што направите потпуно прилагођену уградњу, вреди знати шта је већ доступно из кутије. Јавна страница сваке награде садржи готове исечке за дељење и уградњу које примаоци могу директно да копирају, без икаквог кода са њихове стране:

Public share page with social buttons + embed snippets

Ако је ваш случај „нека прималац покаже да је његова значка права“, упућивање на његову страницу badges.ninja/awards/<guid> често је једноставније од прављења прилагођеног видџета — то је страница за људе приказана раније и она већ води рачуна о разлици између верификованог и опозваног. Прилагођени видџет из овог текста направите када вам је статус верификације потребан приказан унутар интерфејса вашег производа — партнерски именик, интерна табла за ревизију, алат за запошљавање који проверава кандидатове наведене сертификате — где упућивање на други сајт није право корисничко искуство.

Зашто не iframe или видџет добављача?

Неке платформе дају исечак попут <iframe src="https://vendor.example.com/verify-widget"> за уградњу статуса верификације. Ради, али са стварним ценама: не можете да прилагодите садржај изгледу свог сајта (заглављени сте са CSS-ом који је добављач испоручио), уводи cross-origin документ који ваша Content-Security-Policy мора изричито да дозволи, и при сваком учитавању странице шаље се захтев хосту iframe-а треће стране без обзира на то да ли посетиоца уопште занима статус верификације. Видџет са два fetch позива избегава све три ствари — то је ваш DOM, ваш стил и покреће се само кад ви одлучите да га позовете.

Обилазак читавог ланца верификације

Ако градите нешто темељније од видџета за статус — рецимо алат за ревизију који проверава групу сертификата или извештај о усклађености — обиђите цео ланац уместо да станете на assertion-у. Assertion упућује на URL badge (BadgeClass: назив, опис, критеријуми), а BadgeClass даље упућује на URL issuer (профил организације). Ригорозан верификатор разрешава сва три и потврђује да су међусобно доследна — значка заиста припада издаваоцу за кога се декларише, assertion заиста упућује на значку на коју тврди — а не само да assertion највишег нивоа враћа 200. То је више дубине него што видџет за статус једног сертификата захтева, али вреди знати да тај облик постоји ако партнер или ревизор икада упита: „докле заправо сеже ваша верификација?“

Уобичајене грешке које треба избегавати

  • Провера само HTTP статуса. Као што је објашњено, опозван assertion се и даље разрешава. Увек читајте assertion.revoked, не закључујте верификацију само из статусног кода.
  • Чврсто кодиран ID награде у дељеној компоненти. Ако је видџет намењен вишекратној употреби на страницама многих прималаца, ID награде узимајте као параметар (data атрибут, query string, prop), а не као литерал уграђен у скрипту.
  • Тихо гутање мрежних грешака. try/catch који ништа не логује и приказује исти текст „није пронађено“ као за стварно непостојећу значку касније отежава отклањање грешака. Разликујте „мрежни позив није успео“ од „API је рекао не“ у гранама за грешке, макар у логовима.
  • Поновна верификација при сваком рендеровању у клијентској апликацији. Ако видџет живи унутар React или Vue компоненте која се често поново рендерује, верификујте једном по монтирању (или једном по прозору кешираног TTL-а, према одељку о кеширању изнад), а не при сваком рендеровању.

Да ли кошта кредите и да ли ради на бесплатном плану?

Не. Endpoint за верификацију је намерно ван система кредита који управља издавањем — провера да ли је значка важећа не кошта издаваоца ништа и не захтева да посетилац који га зове има налог, API кључ или било који ниво плана. То важи без обзира на то да ли је значка издата на плану Free, Starter или Pro: верификација је својство самог сертификата, а не функција ограничена претплатом издаваоца. Зато овај видџет можете безбедно да поставите на јавну страницу са непредвидивим саобраћајем (страница за каријеру, партнерски именик) без бриге о ограничењима брзине везаним за ваш налог — зовете јавни endpoint само за читање, а не аутентикирану API руту.

Једну ствар вреди изричито нагласити: JSON assertion-а који endpoint враћа не садржи сирову имејл адресу примаоца. Имејл примаоца се на бекенду чува хеширан управо да се јавни одговор верификације не би могао сакупљати ради личних контакт података — добијате довољно да потврдите сертификат (значка, издавалац, датуми, статус опозива), а да се endpoint не претвори у алат за прикупљање потенцијалних клијената за свакога ко прелиста ID-јеве награда.

Спремни да издате свој први верификабилни сертификат?

Почните бесплатно на badges.ninja — визуелни дизајнер, јавна страница за верификацију, PDF сертификат, Open Badge v2.0 излаз. Кредитна картица није потребна.

За потпуну анотирану структуру сваког поља у assertion-у погледајте референцу JSON-LD поља. А ако сертификате издајете програмски, а не само верификујете, API quickstart покрива аутентикацију и позив за креирање награде из ког потиче излаз овог endpoint-а.

Nacho Coll

О аутору

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.

Назад на блог

Повезани чланци