queueit/knownuserv3

Queue-it 安全框架用于确保最终用户不能通过在您的服务器上添加服务器端集成来绕过队列。

3.7.1 2022-09-30 06:53 UTC

README

在开始之前,请阅读 文档,以便了解服务器端连接器。

此连接器支持 PHP >= 5.3.3。

您可以在 此处 找到最新发布的版本,以及 此处 的 Packagist 包。

实现

必须在 所有请求上执行 KnownUser 验证,除了静态和缓存的页面请求、图像、CSS 文件等资源请求。因此,如果您将 KnownUser 验证逻辑添加到中央位置,请确保仅触发页面请求(包括 AJAX 请求),而不是例如图像。

如果我们已经将 integrationconfig.json 复制到位于 Web 应用程序文件夹内其他 knownuser 文件旁边的文件夹中,那么以下方法就是验证用户是否通过队列的必要方法

require_once( __DIR__ .'Models.php');
require_once( __DIR__ .'KnownUser.php');

$configText = file_get_contents('integrationconfig.json');
$customerID = ""; //Your Queue-it customer ID
$secretKey = ""; //Your 72 char secret key as specified in Go Queue-it self-service platform

$queueittoken = isset( $_GET["queueittoken"] )? $_GET["queueittoken"] :'';

try
{
    $fullUrl = getFullRequestUri();
    $currentUrlWithoutQueueitToken = preg_replace("/([\\?&])("."queueittoken"."=[^&]*)/i", "", $fullUrl);

    //Verify if the user has been through the queue
    $result = QueueIT\KnownUserV3\SDK\KnownUser::validateRequestByIntegrationConfig(
       $currentUrlWithoutQueueitToken, $queueittoken, $configText, $customerID, $secretKey);
		
    if($result->doRedirect())
    {
        //Adding no cache headers to prevent browsers to cache requests
        header("Expires:Fri, 01 Jan 1990 00:00:00 GMT");
        header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
        header("Pragma: no-cache");
        //end
    
        if(!$result->isAjaxResult)
        {
            //Send the user to the queue - either because hash was missing or because is was invalid
            header('Location: ' . $result->redirectUrl);		            
        }
        else
        {
            header('HTTP/1.0: 200');
            header($result->getAjaxQueueRedirectHeaderKey() . ': ' . $result->getAjaxRedirectUrl());            
            header("Access-Control-Expose-Headers" . ': ' . $result->getAjaxQueueRedirectHeaderKey());            
        }
		
        die();
    }
    if(!empty($queueittoken) && $result->actionType == "Queue")
    {        
	//Request can continue - we remove queueittoken form querystring parameter to avoid sharing of user specific token
        header('Location: ' . $currentUrlWithoutQueueitToken);
	die();
    }
}
catch(\Exception $e)
{
    // There was an error validating the request
    // Use your own logging framework to log the error
    // This was a configuration error, so we let the user continue
}

获取当前 URL 的辅助方法(您可以使用自己的方法)。此辅助方法的结果用于匹配触发器和作为目标 URL(将用户返回的地方)。因此,结果必须是用户浏览器中的确切 URL,这是非常重要的。

因此,如果您的 Web 服务器位于例如负载均衡器后面,该负载均衡器会修改主机名或端口,则需要根据需要重新格式化辅助方法。

 function getFullRequestUri()
 {
     // Get HTTP/HTTPS (the possible values for this vary from server to server)
    $myUrl = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] && !in_array(strtolower($_SERVER['HTTPS']),array('off','no'))) ? 'https' : 'http';
    // Get domain portion
    $myUrl .= '://'.$_SERVER['HTTP_HOST'];
    // Get path to script
    $myUrl .= $_SERVER['REQUEST_URI'];
    // Add path info, if any
    if (!empty($_SERVER['PATH_INFO'])) $myUrl .= $_SERVER['PATH_INFO'];

    return $myUrl; 
 }

使用内联队列配置实现

在代码中指定配置,而不使用触发器/操作范式。在这种情况下,仅需要排队页面请求,而不是对资源请求。这可以通过在调用 KnownUser::resolveQueueRequestByLocalConfig() 方法之前添加自定义过滤逻辑来实现。

以下是如何在代码中指定配置的示例

require_once( __DIR__ .'Models.php');
require_once( __DIR__ .'KnownUser.php');

$customerID = ""; //Your Queue-it customer ID
$secretKey = ""; //Your 72 char secret key as specified in Go Queue-it self-service platform

$eventConfig = new QueueIT\KnownUserV3\SDK\QueueEventConfig();
$eventConfig->eventId = ""; // ID of the queue to use
$eventConfig->queueDomain = "xxx.queue-it.net"; //Domain name of the queue.
//$eventConfig->cookieDomain = ".my-shop.com"; //Optional - Domain name where the Queue-it session cookie should be saved.
$eventConfig->cookieValidityMinute = 15; //Validity of the Queue-it session cookie should be positive number.
$eventConfig->extendCookieValidity = true; //Should the Queue-it session cookie validity time be extended each time the validation runs? 
//$eventConfig->culture = "da-DK"; //Optional - Culture of the queue layout in the format specified here: https://msdn.microsoft.com/en-us/library/ee825488(v=cs.20).aspx. If unspecified then settings from Event will be used.
// $eventConfig->layoutName = "NameOfYourCustomLayout"; //Optional - Name of the queue layout. If unspecified then settings from Event will be used.

$queueittoken = isset( $_GET["queueittoken"] )? $_GET["queueittoken"] :'';

try
{
    $fullUrl = getFullRequestUri();
    $currentUrlWithoutQueueitToken = preg_replace("/([\\?&])("."queueittoken"."=[^&]*)/i", "", $fullUrl);

    //Verify if the user has been through the queue
    $result = QueueIT\KnownUserV3\SDK\KnownUser::resolveQueueRequestByLocalConfig(
       $currentUrlWithoutQueueitToken, $queueittoken, $eventConfig, $customerID, $secretKey);
	
    if($result->doRedirect())
    {
        //Adding no cache headers to prevent browsers to cache requests
        header("Expires:Fri, 01 Jan 1990 00:00:00 GMT");
        header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
        header("Pragma: no-cache");
        //end
	 if(!$result->isAjaxResult)
        {
            //Send the user to the queue - either because hash was missing or because is was invalid
            header('Location: ' . $result->redirectUrl);		            
        }
        else
        {
            header('HTTP/1.0: 200');
            header($result->getAjaxQueueRedirectHeaderKey() . ': '. $result->getAjaxRedirectUrl());            
            header("Access-Control-Expose-Headers" . ': ' . $result->getAjaxQueueRedirectHeaderKey());            
        }
        
        die();
    }
    if(!empty($queueittoken) && $result->actionType == "Queue")
    {        
	//Request can continue - we remove queueittoken form querystring parameter to avoid sharing of user specific token
        header('Location: ' . $currentUrlWithoutQueueitToken);
	die();
    }
}
catch(\Exception $e)
{
    // There was an error validating the request
    // Use your own logging framework to log the error
    // This was a configuration error, so we let the user continue
}

请求体触发器(高级)

连接器支持在请求体内容上触发。一个例子可能是一个带有特定项目 ID 的 POST 调用,其中您希望最终用户排队。为了使其工作,您需要联系 Queue-it 支持或在您的 GO Queue-it 平台账户的集成设置中启用请求体触发器。一旦启用,您需要更新您的集成,以便请求体可供连接器使用。
您需要创建一个类似于以下的新上下文提供程序

class HttpRequestBodyProvider extends QueueIT\KnownUserV3\SDK\HttpRequestProvider
{
    function getRequestBodyAsString()
    {
        $requestBody = file_get_contents('php://input');

        if(isset($requestBody)){
            return $requestBody;
        }
        else{
            return '';            
        }
    }
}

然后使用它代替默认的 HttpRequestProvider

// Default implementation of HttpRequestProvider always returns empty string as request body. 
// Use following line to set a custom httpRequestBodyProvider
QueueIT\KnownUserV3\SDK\KnownUser::setHttpRequestProvider(new HttpRequestBodyProvider());