שילוב LTI עבור פלטפורמת ה-LMS שלך

שילוב כלים חינוכיים חיצוניים ב-LMS הופך לעיתים קרובות לשרשרת של שגיאות תצורה וחוסר תאימות גרסאות. אנחנו בונים פלטפורמות LMS עם תמיכה מלאה באינטגרציות LTI, כולל חיבור כלים והעברה לסטנדרטים עדכניים. הצוות שלנו מספק את הפרויקט במפתח מלא—מביקורת ועד תמיכה שוטפת—ומבטיח פעילות יציבה ומאובטחת של הסביבה החינוכית שלכם.

פיתוח ותחזוקה של כל סוגי האתרים:

אתרי מידע או יישומי אינטרנט
אתרי תדמית, דפי נחיתה, אתרי חברה, קטלוגים מקוונים, חידונים, אתרי קידום, בלוגים, מקורות חדשות, פורטלי מידע, פורומים, אגרגטורים
אתרי מסחר אלקטרוני או יישומי אינטרנט
חנויות מקוונות, פורטלי B2B, שווקים, בורסות מקוונות, אתרי קאשבק, בורסות, פלטפורמות דרופשיפינג, מנתחי מוצרים
יישומי אינטרנט לניהול תהליכים עסקיים
מערכות CRM, מערכות ERP, פורטלים ארגוניים, מערכות ניהול ייצור, מנתחי מידע
אתרי שירות אלקטרוני או יישומי אינטרנט
פלטפורמות מודעות, בתי ספר מקוונים, בתי קולנוע מקוונים, בוני אתרים, פורטלים לשירותים אלקטרוניים, פלטפורמות אירוח וידאו, פורטלים נושאיים

אלה רק חלק מהסוגים הטכניים של אתרים שאנו עובדים איתם, ולכל אחד מהם יכולים להיות מאפיינים ופונקציונליות ספציפיים משלו, וכן ניתן להתאים אותם לצרכים ולמטרות הספציפיים של הלקוח.

השירותים שאנו מציעים
מציג 1 מתוך 1כל 2062 השירותים
שילוב LTI עבור פלטפורמת ה-LMS שלך
מורכב
מ- 2 שבועות עד 3 חודשים

הכישורים שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1365
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1330
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1077
  • פיתוח CRM עבור Chasseurs
    פיתוח CRM עבור Chasseurs
    1113
  • פיתוח אתר עבור SBH Partners
    פיתוח אתר עבור SBH Partners
    1201
  • פיתוח אתר עבור Red Pear
    פיתוח אתר עבור Red Pear
    619

שילוב LTI נכשל לעיתים קרובות עקב אי-התאמות גרסאות, אובדן סשן או תצורת JWKS שגויה. המהנדסים שלנו פותרים בעיות אלה מקצה לקצה—מביקורת על ה-LMS הנוכחי שלך ועד חיבור כל כלי תואם LTI. צברנו ספרייה של שגיאות טיפוסיות ותבניות מוכנות, מה שמקצר משמעותית את זמן הפיתוח.

לפי מפרט IMS Global LTI 1.3, שימוש ב-OAuth 2.0 ו-JWKS מספק רמת אבטחה גבוהה יותר בהשוואה ל-LTI 1.1.

למה LTI 1.3 עדיף על LTI 1.1?

LTI 1.1 משתמש ב-OAuth 1.0—פרוטוקול מיושן עם חתימות שבריריות. LTI 1.3 מבוסס על OAuth 2.0 ו-OpenID Connect: מאובטח יותר, שקוף וקל יותר לניפוי שגיאות. אסימוני JWT עם מפתחות JWKS מונעים זיוף בקשות. ספקים רבים (Coursera, Zoom, Adobe) עוברים ל-LTI 1.3—בלעדיו, לא תוכל לחבר כלים מודרניים.

תכונה LTI 1.1 LTI 1.3
פרוטוקול OAuth 1.0 OAuth 2.0 + OIDC
חתימה HMAC-SHA1 RSA/JWT
ניהול מפתחות סוד משותף (סטטי) JWKS (רוטציה)
אבטחה נמוכה גבוהה
זמן אינטגרציה 2-3 ימים 3-5 ימים

כיצד אנו מגדירים LTI 1.3 ב-LMS שלך

ה-LMS משמש כפלטפורמה (לפי IMS). אנו מאתחלים את התהליך באמצעות OIDC Login Request ומייצרים JWT. להלן קוד טיפוסי עם ספריית ltijs:

import { Provider } from 'ltijs'; // npm install ltijs
// Настройка LMS как LTI Platform
Provider.setup(
  process.env.LTI_ENCRYPTION_KEY!, // 32+ символов для шифрования cookies
  {
    url: process.env.DATABASE_URL!,
    plugin: require('ltijs-postgresql'), // адаптер для PostgreSQL
  },
  {
    cookies: {
      secure: true,
      sameSite: 'None',
    },
    devMode: process.env.NODE_ENV !== 'production',
  }
);

// Регистрация внешнего инструмента
await Provider.registerPlatform({
  url: 'https://tool.example.com',
  name: 'Kahoot Integration',
  clientId: process.env.KAHOOT_CLIENT_ID!,
  authenticationEndpoint: 'https://tool.example.com/lti/auth',
  accesstokenEndpoint: 'https://tool.example.com/lti/token',
  authConfig: {
    method: 'JWK_SET',
    key: 'https://tool.example.com/.well-known/jwks.json',
  },
});

// Обработчик запуска инструмента
Provider.onConnect(async (token, req, res) => {
  const { email, name, role } = token.userInfo;
  const contextId = token.platformContext.context?.id;
  // Проверить/создать пользователя во внешнем инструменте
  res.json({ token: token.jwt });
});

await Provider.deploy({ serverless: true });

LTI 1.1—לכלים מדור קודם

חלק מהספקים (Phet, מבחנים מסוימים) עדיין משתמשים ב-LTI 1.1 עם חתימת OAuth 1.0:

import oauth from 'oauth-signature';

function launchLti11(
  launchUrl: string,
  consumerKey: string,
  consumerSecret: string,
  params: Record<string, string>
): { url: string; method: 'POST'; body: string } {
  const baseParams: Record<string, string> = {
    lti_message_type: 'basic-lti-launch-request',
    lti_version: 'LTI-1p0',
    oauth_callback: 'about:blank',
    oauth_consumer_key: consumerKey,
    oauth_nonce: crypto.randomUUID().replace(/-/g, ''),
    oauth_signature_method: 'HMAC-SHA1',
    oauth_timestamp: String(Math.floor(Date.now() / 1000)),
    oauth_version: '1.0',
    ...params,
  };

  const signature = oauth.generate('POST', launchUrl, baseParams, consumerSecret, '');
  baseParams.oauth_signature = signature;

  const body = new URLSearchParams(baseParams).toString();
  return { url: launchUrl, method: 'POST', body };
}

// Страница запуска LTI инструмента
app.get('/courses/:courseId/tools/:toolId/launch', authenticate, async (req, res) => {
  const tool = await db.ltiTools.findById(req.params.toolId);
  const enrollment = await db.enrollments.findByCourseAndUser(
    req.params.courseId,
    req.user.id
  );

  if (tool.version === '1.1') {
    const launch = launchLti11(tool.launch_url, tool.consumer_key, tool.consumer_secret, {
      resource_link_id: `${req.params.courseId}-${req.params.toolId}`,
      resource_link_title: tool.name,
      user_id: req.user.id,
      lis_person_name_full: req.user.name,
      lis_person_contact_email_primary: req.user.email,
      roles: enrollment.role === 'instructor' ? 'Instructor' : 'Student',
      context_id: req.params.courseId,
      context_title: enrollment.courseTitle,
    });

    // Авто-сабмит форму через HTML
    res.send(`
      <!DOCTYPE html>
      <html>
      <body>
        <form id="lti" method="POST" action="${launch.url}">
          ${Object.entries(Object.fromEntries(new URLSearchParams(launch.body)))
            .map(([k, v]) => `<input type="hidden" name="${k}" value="${v}" />`)
            .join('\n')}
        </form>
        <script>document.getElementById('lti').submit();</script>
      </body>
      </html>
    `);
  }
});

שמירת תצורת כלי

CREATE TABLE lti_tools (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    course_id UUID REFERENCES courses(id),
    name VARCHAR(255) NOT NULL,
    version VARCHAR(10) NOT NULL, -- '1.1' | '1.3'
    -- LTI 1.1
    launch_url TEXT,
    consumer_key VARCHAR(255),
    consumer_secret TEXT,
    -- LTI 1.3
    client_id VARCHAR(255),
    platform_id VARCHAR(255),
    deployment_id VARCHAR(255),
    oidc_auth_url TEXT,
    jwks_url TEXT,
    -- Настройки
    open_in_new_tab BOOLEAN DEFAULT false,
    custom_params JSONB DEFAULT '{}',
    created_at TIMESTAMPTZ DEFAULT now()
);

קבלת תוצאות דרך LTI Outcomes (1.1)

// Инструмент может отправить оценку обратно в LMS
app.post('/lti/grade', async (req, res) => {
  const { sourcedId, score, action } = parseLtiOutcomesXml(req.body);
  // sourcedId содержит userId и resourceLinkId
  const [userId, resourceId] = parseLisResultSourcedId(sourcedId);
  await db.ltiGrades.upsert({
    userId,
    resourceId,
    score: Number(score),
    receivedAt: new Date(),
  });
  // Обновить прогресс курса
  await updateCourseProgress(userId, resourceId, Number(score));
  res.type('application/xml').send(`
    <?xml version="1.0" encoding="UTF-8"?>
    <imsx_POXEnvelopeResponse xmlns="http://www.imsglobal.org/services/ltiv1p1/xsd/imsoms_v1p0">
      <imsx_POXHeader>
        <imsx_POXResponseHeaderInfo>
          <imsx_version>V1.0</imsx_version>
          <imsx_messageIdentifier>${crypto.randomUUID()}</imsx_messageIdentifier>
          <imsx_statusInfo>
            <imsx_codeMajor>success</imsx_codeMajor>
            <imsx_severity>status</imsx_severity>
          </imsx_statusInfo>
        </imsx_POXResponseHeaderInfo>
      </imsx_POXHeader>
      <imsx_POXBody><replaceResultResponse /></imsx_POXBody>
    </imsx_POXEnvelopeResponse>
  `);
});

מה כלול בעבודת אינטגרציית LTI?

  • ביקורת על ארכיטקטורת ה-LMS הנוכחית: זיהוי צווארי בקבוק (שאילתות N+1, אובדן סשן), הערכת תאימות לכלים הנדרשים.
  • עיצוב סכמת אחסון לתצורות כלים (טבלת lti_tools עם תמיכה בשתי גרסאות LTI).
  • הטמעת תהליך השקה של LTI 1.1 ו/או LTI 1.3 על המחסנית שלך (Node.js, Python, PHP, Ruby—כל אחת).
  • אינטגרציה עם כלי חיצוני: רישום, השקת בדיקה, החזרת ציונים (Outcomes).
  • כתיבת תיעוד למנהלי מערכת ולמרצים על הוספת כלים חדשים.
  • הכשרת הצוות שלך: כיצד לנפות שגיאות, לעדכן מפתחות, לעבוד עם JWKS.
  • תמיכה של 30 יום לאחר השחרור: תיקוני באגים, ייעוץ.
שגיאות נפוצות באינטגרציית LTI
  • אי-התאמת סוג משתמש: בלבול בין תפקידי Instructor ו-Student ב-JWT.
  • שגיאות JWKS: מפתחות פגים או לא מעודכנים.
  • בעיות CORS: כלים חיצוניים חוסמים בקשות.
  • תצורת OIDC Login Request שגויה: URI הפנייה שגוי.

לוחות זמנים ועלות

אינטגרציית LTI 1.1 (Consumer + Launch + Grades) — 3–5 ימים. LTI 1.3 עם תהליך OIDC — שבוע. תמיכה בשתי הגרסאות בתוספת ממשק ניהול כלים — שבועיים. העלות נקבעת באופן אישי, ושימוש בתבניות מוכנות יכול להפחית משמעותית את התקציב.

הניסיון והאחריות שלנו

מקרה בוחן: שילוב Kahoot ב-LMS אוניברסיטאי. נדרשה תמיכה ב-LTI 1.3, מכיוון ש-Kahoot עבר לסטנדרט החדש. הטמענו את תהליך OIDC, הגדרנו JWKS ובדקנו החזרת ציונים. כתוצאה מכך, הסטודנטים קיבלו ממשק אחיד ללא אימות חוזר. קבלו ייעוץ על אינטגרציית LTI עוד היום. צרו קשר – נעריך את המשימה שלכם ונציע פתרון תוך 2 ימי עסקים.