eskater / lti-1p3-tool
Requires
- firebase/php-jwt: ^5.2
- phpseclib/phpseclib: ^2.0
This package is auto-updated.
Last update: 2024-09-10 08:46: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 install
或 composer 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或注册不存在,将抛出 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'; }
访问缓存的启动请求
在后续请求中,您可能会希望回溯到某个启动(launch)。这可以通过使用启动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)。如果没有默认行项目存在,它将创建一个。
如果您想发送多种类型的成绩,可以通过指定一个LTI\LTI_Lineitem
来实现。
$lineitem = LTI\LTI_Lineitem::new() ->set_tag('grade') ->set_score_maximum(100) ->set_label('Grade'); $ags->put_grade($grade, $lineitem);
如果存在具有相同tag
的行项目,则使用该行项目;否则,将创建一个新的行项目。
贡献
如果您有改进、建议或错误修复,请随时提交pull request或issue,有人会查看。
您不需要是IMS成员即可使用或为此库做出贡献,但是为了更好地访问支持资源和认证,我们建议这样做。
此库最初由Turnitin的@MartinLenord创建,以帮助验证LTI 1.3规范并加速工具开发。
注意:此库仅适用于基于IMS LTI 1.3的规范。包含自定义、非规范或供应商特定的更改的请求将被拒绝。
不喜欢PHP?
如果您不喜欢PHP,并且有一个您希望为其创建库的喜欢的语言,我们非常愿意听取您的意见!