vfork-imsglobal/lti-1p3-tool

LTI 1.3 工具分支

dev-master 2024-02-28 16:24 UTC

This package is not auto-updated.

Last update: 2024-09-25 20:35:26 UTC


README

LTI 1.3 优势库

此代码包括用于在 PHP 中创建 LTI 工具提供者的库。

库文档

导入库

使用 Composer

将以下内容添加到您的 composer.json 文件中

"repositories": [
    {
        "type": "vcs",
        "url": "https://github.com/IMSGlobal/lti-1-3-php-library"
    }
],
"require": {
    "imsglobal/lti-1p3-tool": "dev-master"
}

运行 composer installcomposer update。在您的代码中,您现在可以使用 \IMSGlobal\LTI 命名空间中的类来访问库。

手动导入

要导入库,将 src 中的 lti 文件夹复制到您的项目中,并在执行开始时使用以下代码

require_once('lti/lti.php');
use \IMSGlobal\LTI;

访问注册数据

为了允许进行验证并允许工具知道它需要在何处进行调用,必须存储注册数据。库而不是指定如何存储,它提供了一个必须实现的接口,以便它可以访问注册数据。必须完全实现 LTI\Database 接口才能使其工作。

class Example_Database implements LTI\Database {
    public function find_registration_by_issuer($iss) {
        ...
    }
    public function find_deployment($iss, $deployment_id) {
        ...
    }
}

必须返回一个 LTI\LTI_Registration

return LTI\LTI_Registration::new()
    ->set_auth_login_url($auth_login_url)
    ->set_auth_token_url($auth_token_url)
    ->set_client_id($client_id)
    ->set_key_set_url($key_set_url)
    ->set_kid($kid)
    ->set_issuer($issuer)
    ->set_tool_private_key($private_key);

如果存在于数据库中,则必须返回一个 LTI\LTI_Deployment

return LTI\LTI_Deployment::new()
    ->set_deployment_id($deployment_id);

调用库需要传入一个 LTI\Database 实例。

创建 JWKS 端点

可以为单个注册或从 KID 和私有密钥的数组生成 JWKS(JSON Web Key Set)端点。

// From issuer
LTI\JWKS_Endpoint::from_issuer(new Example_Database(), 'http://example.com')->output_jwks();
// From registration
LTI\JWKS_Endpoint::from_registration($registration)->output_jwks();
// From array
LTI\JWKS_Endpoint::new(['a_unique_KID' => file_get_contents('/path/to/private/key.pem')])->output_jwks();

处理请求

Open Id Connect 登录请求

LTI 1.3 使用 OpenId Connect 第三方发起的登录流的修改版本。这意味着要进行 LTI 1.3 启动,您必须首先接收登录初始化请求并返回到平台。

为了处理此请求,您必须首先创建一个新的 LTI\LTI_OIDC_Login 对象。

$login = LTI_OIDC_Login::new(new Example_Database());

现在您必须配置您的登录请求,并带有返回 URL(此 URL 必须预先配置并在工具中白名单)。如果没有给出重定向 URL 或注册不存在,则将抛出 LTI\OIDC_Exception

try {
    $redirect = $login->do_oidc_login_redirect("https://my.tool/launch");
} catch (LTI\OIDC_Exception $e) {
    echo 'Error doing OIDC login';
}

有了重定向,我们现在可以将用户重定向回工具。有三种方法可以做到这一点

这将添加一个 302 位置头并退出。

$redirect->do_redirect();

这将输出一些 JavaScript 以执行重定向而不是使用 302。

$redirect->do_js_redirect();

您还可以获取您需要重定向到的 URL,其中包含所有必要的查询参数,如果您希望以自定义方式重定向。

$redirect_url = $redirect->get_redirect_url();

重定向完成,我们可以进行启动。

LTI 消息启动

现在我们已经完成了 OIDC 登录,平台将返回到工具。为了处理此请求,首先我们需要创建一个新的 LTI\LTI_Message_Launch 对象。

$launch = LTI\LTI_Message_Launch::new(new Example_Database());

一旦我们有了消息启动,我们就可以对其进行验证。这将检查签名、部署的存在以及任何必需的参数。如果验证失败,则将抛出异常。

try {
    $launch->validate();
} catch (Exception $e) {
    echo 'Launch validation failed';
}

现在我们知道启动是有效的,我们可以了解更多关于启动的信息。

检查我们是否有资源启动或深度链接启动。

if ($launch->is_resource_launch()) {
    echo 'Resource Launch!';
} else if ($launch->is_deep_link_launch()) {
    echo 'Deep Linking Launch!';
} else {
    echo 'Unknown launch type';
}

检查我们可以访问哪些服务。

if ($launch->has_ags()) {
    echo 'Has Assignments and Grades Service';
}
if ($launch->has_nrps()) {
    echo 'Has Names and Roles Service';
}

访问缓存的启动请求

您可能会希望稍后在后续请求中回过头来引用启动。这是使用启动 ID 来标识缓存的请求完成的。启动 ID 可以使用以下方法找到

$launch_id = $launch->get_launch_id().

一旦您获得启动ID,就可以将其与您的会话链接,并将其作为查询参数传递。

请确保您将启动ID与用户会话进行核对,以防止有人对另一个人的启动进行操作。

使用启动ID检索启动可以通过以下方式完成:

$launch = LTI_Message_Launch::from_cache($launch_id, new Example_Database());

检索后,您可以像平常一样调用启动对象上的任何方法,例如:

if ($launch->has_ags()) {
    echo 'Has Assignments and Grades Service';
}

深度链接响应

如果您收到深度链接启动,您很可能希望使用平台资源来响应深度链接请求。

要创建深度链接响应,您需要获取当前启动的深度链接。

$dl = $launch->get_deep_link();

现在我们需要创建 LTI\LTI_Deep_Link_Resource 来返回。

$resource = LTI\LTI_Deep_Link_Resource::new()
    ->set_url("https://my.tool/launch")
    ->set_custom_params(['my_param' => $my_param])
    ->set_title('My Resource');

一切设置都是为了将资源返回到平台。有两种方式可以实现。

以下方法将为您输出一个自动发布表单的html。

$dl->output_response_form([$resource]);

或者,您可以直接调用以获取需要发送回平台的已签名JWT。

$dl->get_response_jwt([$resource]);

调用服务

名称和角色服务

在开始使用名称和角色之前,您应该检查您是否有权限访问它。

if (!$launch->has_nrps()) {
    throw new Exception("Don't have names and roles!");
}

一旦我们知道我们可以访问它,我们可以从启动中获取该服务的实例。

$nrps = $launch->get_nrps();

从服务中,我们可以通过调用来获取所有成员的数组

$members = $nrps->get_members();

作业和成绩服务

在开始使用作业和成绩之前,您应该检查您是否有权限访问它。

if (!$launch->has_ags()) {
    throw new Exception("Don't have assignments and grades!");
}

一旦我们知道我们可以访问它,我们可以从启动中获取该服务的实例。

$ags = $launch->get_ags();

要将成绩发送回平台,您需要创建一个 LTI\LTI_Grade 对象,并用必要的信息填充它。

$grade = LTI\LTI_Grade::new()
    ->set_score_given($grade)
    ->set_score_maximum(100)
    ->set_timestamp(date(DateTime::ISO8601))
    ->set_activity_progress('Completed')
    ->set_grading_progress('FullyGraded')
    ->set_user_id($external_user_id);

要将成绩发送到平台,我们可以调用

$ags->put_grade($grade);

这会将成绩放入默认提供的lineitem。如果没有默认lineitem,则会创建一个。

如果您想发送多种类型的成绩,可以通过指定一个 LTI\LTI_Lineitem 来实现。

$lineitem = LTI\LTI_Lineitem::new()
    ->set_tag('grade')
    ->set_score_maximum(100)
    ->set_label('Grade');

$ags->put_grade($grade, $lineitem);

如果存在具有相同 tag 的lineitem,将使用该lineitem,否则将创建一个新的lineitem。

贡献

如果您有改进、建议或错误修复,请随意发起pull请求或issue,有人会查看它。

您不需要成为IMS成员即可使用或为此库做出贡献,但是为了更好地获取支持资源并获得认证,建议您这样做。

此库最初由@MartinLenord从Turnitin创建,以帮助验证LTI 1.3规范并加速工具开发。

注意: 此库仅适用于基于IMS LTI 1.3的规范。请求包含自定义、非规范或供应商特定更改的请求将被拒绝。

不喜欢PHP?

如果您不喜欢PHP,并且有一个您想要为其制作库的喜欢的语言,我们很乐意听到您的意见!