Benamkan Pengesahan Lencana di Laman Web Anda (Tanpa Iframe, Tanpa SDK)

Tambah serpihan JavaScript kecil (atau fetch di sisi pelayan) pada laman web anda untuk mengesahkan mana-mana Open Badge melalui endpoint JSON-LD awam. Tanpa iframe, tanpa penjejak pihak ketiga.

Nacho Coll Oleh Dikemas kini 9 minit bacaan
Tambah serpihan JavaScript kecil (atau fetch di sisi pelayan) pada laman web anda untuk mengesahkan mana-mana Open Badge melalui endpoint JSON-LD awam. Tanpa iframe, tanpa penjejak pihak ketiga.

Jika anda mengeluarkan kelayakan, lambat laun akan ada yang bertanya: “bagaimana saya tahu lencana ini tulen?” Jawapan jujurnya tidak sepatutnya “percayalah pada PNG itu.” Open Badge v2.0 menyelesaikannya dengan endpoint pengesahan awam yang boleh dibaca mesin, dan memasang widget “Disahkan” di laman web anda sendiri hanya memerlukan kira-kira sepuluh baris kod — bukan iframe, bukan skrip benam pihak ketiga, dan bukan SDK.

Catatan ini menunjukkan dengan tepat cara memanggil endpoint tersebut dan memaparkan hasilnya, dalam JavaScript biasa serta di sisi pelayan menggunakan Node dan Python. Ia juga merangkumi apa yang sebenarnya diperiksa oleh “pengesahan”, kedudukan endpoint ini berbanding halaman untuk manusia yang sudah disediakan badges.ninja kepada penerima, dan kesilapan yang menjadikan widget pengesahan nampak siap sedangkan hakikatnya tidak membuktikan apa-apa.

Apa maksud sebenar “disahkan”

Assertion Open Badge v2.0 ialah dokumen JSON-LD dengan bentuk tetap: assertion itu sendiri (siapa yang menerimanya, bila), rujukan kepada BadgeClass (apa ia, siapa yang menentukan kriteria), dan rujukan kepada profil pengeluar (siapa yang menjamin). Apabila anda “mengesahkan” sesuatu lencana, sebenarnya anda memeriksa tiga perkara berasingan:

  1. Adakah assertion wujud dan boleh diselesaikan. ID anugerah itu benar, bukan diteka atau diusik.
  2. Adakah ia telah dibatalkan. Pengeluar boleh membatalkan lencana selepas dikeluarkan — kelayakan yang dikeluarkan tersilap, pelanggaran dasar, pensijilan yang tamat tempoh — dan pengesah yang betul mesti menunjukkannya, bukan sekadar mengesahkan rekod itu wujud.
  3. Adakah rantaian itu kukuh. Rujukan badge dan pengeluar dalam assertion benar-benar menyelesaikan kepada rekod sebenar yang sepadan, bukan ID yatim atau tidak sepadan.

Widget pengesahan yang hanya mengakses URL dan menyemak status 200 terlepas pandang perkara 2 sepenuhnya. Assertion yang dibatalkan masih boleh diselesaikan dengan baik — cuma ia membawa bendera pembatalan dalam payload. Jika widget anda hanya menyemak “adakah permintaan berjaya,” kelayakan yang dibatalkan akan dipaparkan sebagai disahkan, dan itu lebih buruk daripada tiada widget langsung.

Halaman awam untuk manusia berbanding endpoint API

Setiap anugerah yang dikeluarkan di https://badges.ninja mendapat URL awam yang boleh dikongsi penerima terus, tanpa perlu mendaftar untuk melihatnya:

Public credential page

Halaman itulah yang akan dipautkan kebanyakan penerima daripada LinkedIn, resume, atau tandatangan e-mel — ia dibina untuk manusia, memaparkan imej lencana, pengeluar dan tarikh dikeluarkan, serta tidak memerlukan apa-apa daripada anda untuk berfungsi. Endpoint API di bawah memulangkan assertion asas yang sama sebagai JSON-LD berstruktur, iaitu apa yang anda perlukan apabila membina UI sendiri dan bukannya sekadar memaut keluar ke UI kami.

Endpoint

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

Tiada header pengesahan diperlukan — ini sengaja dibuat awam, kerana seluruh tujuan Open Badges ialah supaya sesiapa sahaja (majikan, perekrut, lembaga pelesenan) boleh mengesahkan kelayakan tanpa akaun. Butiran kontrak penuh, termasuk nama medan tepat dalam assertion yang dipulangkan, terdapat dalam dokumen pengesahan.

Hantarkan GUID anugerah, yang akan anda perolehi sama ada daripada rekod pengeluaran anda sendiri atau diambil daripada pautan badges.ninja/awards/<guid> yang dikongsi penerima dengan anda.

JS biasa: fetch dan paparkan

Inilah keseluruhan widget. Tiada langkah build, tiada pakej npm, letakkan terus pada mana-mana halaman:

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

Gantikan REPLACE_WITH_AWARD_ID dengan GUID anugerah sebenar. Itulah keseluruhan integrasi di sisi klien: tiada sempadan iframe untuk digelutkan dengan CSS, dan tiada skrip pihak ketiga yang membawa analitik atau piksel penjejakan sendiri bersama semakan pengesahan.

Sisi pelayan: Node

Jika anda lebih suka mengesahkan di backend — contohnya, sebelum memaparkan lencana “Rakan Kongsi Disahkan” pada halaman profil yang anda kawal, atau sebelum menerima kelayakan sebagai bukti dalam aliran onboarding — fetch-nya serupa tanpa bahagian 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 };
}

Sisi pelayan: 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")}

Kedua-dua contoh menganggap respons bukan 200 sebagai “tidak ditemui” dan bukannya melontar ralat. ID anugerah yang rosak atau diteka ialah input yang dijangka bagi endpoint pengesahan awam, bukan sesuatu yang luar biasa, jadi kendalikannya sebagai cabang biasa dan bukan ralat yang ditangkap.

Menggayakan hasil, bukannya membenamkan UI orang lain

Memandangkan widget di atas hanyalah panggilan fetch ke dalam DOM anda sendiri, anda mengawal setiap piksel. Corak lazim ialah tiga keadaan visual yang dipetakan terus daripada respons:

  • Disahkan — tanda semak hijau bersama “Disahkan” dan tarikh dikeluarkan, digayakan agar sepadan dengan komponen badge/tag laman anda.
  • Dibatalkan — keadaan malap atau merah yang menunjukkan sebab pembatalan dan bukannya menyembunyikannya. Penerima dan pihak ketiga sama-sama mendapat manfaat daripada “kenapa” yang jujur, bukan kegagalan senyap.
  • Tidak ditemui — layan sama seperti “dibatalkan” dari segi visual (jangan paparkan keadaan kejayaan palsu), tetapi dengan teks berbeza, kerana ID yang salah dan pembatalan yang disengajakan ialah situasi berbeza bagi sesiapa yang membaca halaman itu.

Semua ini tidak memerlukan pustaka komponen. Satu switch pada verified / revoked / not_found dan tiga kelas CSS sudah mencukupi.

Caching, supaya endpoint tidak dihentam

Endpoint pengesahan ini awam dan tanpa pengesahan identiti, yang juga bermakna tiada kos kredit bagi setiap permintaan — tetapi ia tetap satu pusingan rangkaian pada setiap muat halaman jika anda memanggilnya di sisi klien tanpa caching. Untuk halaman yang memaparkan lencana sama kepada setiap pelawat (lencana “Rakan Kongsi Disahkan” di pengaki, misalnya), cache hasilnya di sisi pelayan dengan TTL pendek — lima hingga lima belas minit sudah memadai, kerana pembatalan bukan isyarat yang berubah pantas — dan bukannya fetch semula pada setiap permintaan:

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

Untuk widget bagi setiap pelawat (penerima yang membenamkan kelayakan sendiri di laman peribadi), langkau cache dan panggil terus semasa halaman dimuat — permintaan tambahan itu boleh diabaikan pada skala sebegitu.

Apa yang sudah disediakan badges.ninja kepada penerima

Sebelum membina benaman yang sepenuhnya tersuai, ada baiknya anda tahu apa yang sedia ada. Halaman awam setiap anugerah termasuk serpihan kongsi dan benam siap pakai yang boleh disalin terus oleh penerima, tanpa sebarang kod di pihak mereka:

Public share page with social buttons + embed snippets

Jika kes penggunaan anda ialah “biar penerima tunjukkan lencana mereka tulen,” memaut ke halaman badges.ninja/awards/<guid> mereka selalunya lebih mudah daripada membina widget tersuai — ia ialah halaman untuk manusia yang ditunjukkan tadi, dan ia sudah mengendalikan pembezaan disahkan/dibatalkan untuk anda. Bina widget tersuai daripada catatan ini apabila anda perlu status pengesahan dipaparkan di dalam UI produk anda sendiri — direktori rakan kongsi, papan pemuka audit dalaman, alat pengambilan pekerja yang menyemak pensijilan yang didakwa calon — di mana memaut keluar ke laman lain bukanlah UX yang sesuai.

Mengapa bukan iframe atau widget vendor?

Sesetengah platform memberi anda serpihan seperti <iframe src="https://vendor.example.com/verify-widget"> untuk membenamkan status pengesahan. Ia berfungsi, tetapi ada kos sebenar: anda tidak boleh menggayakan semula kandungannya agar sepadan dengan laman anda (anda terikat dengan CSS yang dihantar vendor), ia memperkenalkan dokumen lintas-asal yang mesti dibenarkan secara eksplisit oleh Content-Security-Policy anda, dan setiap muat halaman membuat permintaan kepada hos iframe pihak ketiga sama ada pelawat peduli tentang status pengesahan atau tidak. Widget fetch dua panggilan mengelakkan ketiga-tiganya — ia DOM anda, gaya anda, dan ia hanya berjalan apabila anda memutuskan untuk memanggilnya.

Menelusuri keseluruhan rantaian pengesahan

Jika anda membina sesuatu yang lebih teliti daripada widget status — alat audit yang menyemak sekumpulan kelayakan, contohnya, atau laporan pematuhan — telusuri seluruh rantaian dan jangan berhenti pada assertion. Assertion merujuk URL badge (BadgeClass: nama, penerangan, kriteria) dan BadgeClass pula merujuk URL issuer (profil organisasi). Pengesah yang teliti menyelesaikan ketiga-tiganya dan mengesahkan bahawa ia konsisten secara dalaman — lencana itu benar-benar milik pengeluar yang didakwa, assertion benar-benar merujuk badge yang didakwa — bukan sekadar assertion peringkat atas memulangkan 200. Itu lebih mendalam daripada keperluan widget status satu kelayakan, tetapi berguna untuk anda tahu bentuknya wujud jika rakan kongsi atau juruaudit bertanya “sedalam mana sebenarnya pengesahan anda?”

Kesilapan lazim yang perlu dielakkan

  • Hanya menyemak status HTTP. Seperti yang dibincangkan di atas, assertion yang dibatalkan masih boleh diselesaikan. Sentiasa baca assertion.revoked, jangan simpulkan pengesahan daripada kod status semata-mata.
  • Mengekodkan keras ID anugerah dalam komponen kongsi. Jika widget dimaksudkan untuk digunakan semula pada halaman ramai penerima, ambil ID anugerah sebagai parameter (data attribute, query string, prop), bukan literal yang tertanam dalam skrip.
  • Menelan ralat rangkaian secara senyap. try/catch yang tidak mencatat apa-apa dan menunjukkan teks “tidak ditemui” yang sama seperti lencana yang benar-benar tiada menjadikan nyahpepijat menyakitkan kelak. Bezakan “panggilan rangkaian gagal” daripada “API berkata tidak” dalam cabang ralat anda, sekurang-kurangnya dalam log.
  • Mengesahkan semula pada setiap render dalam aplikasi sisi klien. Jika widget berada dalam komponen React atau Vue yang kerap dirender semula, sahkan sekali setiap mount (atau sekali setiap tetingkap TTL cache, mengikut bahagian caching di atas), bukan pada setiap render semula.

Adakah ini menggunakan kredit, dan adakah ia berfungsi pada pelan percuma?

Tidak. Endpoint pengesahan sengaja berada di luar sistem kredit yang mengawal pengeluaran — menyemak sama ada lencana sah tidak membebankan pengeluar apa-apa, dan tidak memerlukan pelawat yang memanggilnya mempunyai akaun, kunci API, atau mana-mana peringkat pelan. Itu benar sama ada lencana dikeluarkan pada pelan Free, Starter atau Pro: pengesahan ialah sifat kelayakan itu sendiri, bukan ciri yang dihadkan oleh langganan pengeluar. Itu juga sebabnya anda boleh meletakkan widget ini dengan selamat pada halaman awam dengan trafik yang tidak dapat diramal (halaman kerjaya, direktori rakan kongsi) tanpa bimbang tentang had kadar yang dikaitkan dengan akaun anda — anda memanggil endpoint awam baca-sahaja, bukan laluan API yang disahkan.

Satu perkara yang perlu dinyatakan dengan jelas: JSON assertion yang dipulangkan endpoint tidak mengandungi alamat e-mel mentah penerima. E-mel penerima disimpan dalam bentuk hash di backend supaya respons pengesahan awam tidak boleh dikikis untuk maklumat hubungan peribadi — apa yang anda terima cukup untuk mengesahkan kelayakan (badge, pengeluar, tarikh, status pembatalan) tanpa menjadikan endpoint itu alat penjanaan prospek untuk sesiapa yang mengulang ID anugerah.

Sedia mengeluarkan kelayakan boleh sah pertama anda?

Mulakan percuma di badges.ninja — pereka visual, halaman pengesahan awam, sijil PDF, output Open Badge v2.0. Tiada kad kredit diperlukan.

Untuk struktur beranotasi penuh bagi setiap medan dalam assertion, lihat rujukan medan JSON-LD. Dan jika anda mengeluarkan kelayakan secara programatik dan bukan sekadar mengesahkannya, panduan mula pantas API merangkumi pengesahan identiti dan panggilan penciptaan anugerah yang menjadi sumber output endpoint ini.

Nacho Coll

Tentang penulis

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.

Kembali ke Blog

Artikel Berkaitan