bizley/yii2-mercure

Yii 2 的 Mercure 发布者。

资助包维护!
bizley

安装量: 1,175

依赖关系: 1

建议者: 0

安全: 0

星标: 5

关注者: 3

分支: 0

开放性问题: 1

类型:yii2-extension

1.0.0 2019-09-20 18:14 UTC

This package is auto-updated.

Last update: 2024-09-02 04:41:11 UTC


README

Latest Stable Version Total Downloads License

将 Mercure 发布者作为 Yii 2 组件

此包为 Yii 2 框架提供组件,用于向 Mercure 中心发布更新。

什么是 Mercure?

引用 dunglas/mercure

Mercure 是一种协议,允许以方便、快速、可靠和节能的方式将数据更新推送到网络浏览器和其他 HTTP 客户端。它特别适用于发布通过 Web API 提供的资源实时更新,用于响应式 Web 和移动应用。

查看相关仓库以了解更多关于 Mercure 的信息。还包括如何设置服务器和客户端以使用 Mercure 协议建立连接的说明。

安装

将包添加到您的 composer.json

{
    "require": {
        "bizley/yii2-mercure": "^1.0"
    }
}

然后运行 composer update,或者也可以运行 composer require bizley/yii2-mercure:^1.0

当然,您还需要 Mercure Hub。有关获取 Hub 的说明,请参阅 dunglas/mercure(我建议使用 Docker 镜像)。

配置

在您的配置文件中添加以下内容

'components' => [
    'mercure' => [
        'class' => \bizley\yii2\mercure\Publisher::class,
        'hubUrl' => 'http://mercure.local/hub', // URL of the Mercure hub
        'jwt' => '...', // string or anonymous function returning string with JWT (see details below)
        'httpClient' => '...', // HTTP client (see details below)
        'useYii2Client' => true, // HTTP client mode (see details below)            
    ],
],

配置详细信息

  • hubUrl Mercure 中心的 URL。
  • jwt JSON Web Token 或返回它的匿名函数。有关更多信息,请参阅 授权 部分。
  • httpClient 带有已注册 HTTP 客户端组件名称的字符串、带有 HTTP 客户端配置的数组,或实际的 HTTP 客户端对象。当 useYii2Client 选项设置为 true(默认)时,此选项应指向 Yii 2 HTTP 客户端 组件。如果您想使用它,您必须像链接中描述的那样安装它,并在配置中注册它(因此您可以将它设置为 'httpClient' => 'client-component-name'),或者为它提供数组配置(如 'httpClient' => ['class' => \yii\httpclient\Client::class])。
  • useYii2Client 布尔标志,表示此组件是否应将 Yii 2 HTTP 客户端 作为 HTTP 客户端(默认为 true)或其他自定义 HTTP 客户端(false)。

用法

应用程序必须携带一个 JSON Web Token(JWT)到 Mercure 中心以获得发布更新的授权。

此 JWT 应存储在前面提到的 jwt 属性中。

JWT 必须使用与 Hub 用于验证 JWT 相同的密钥进行签名(默认 Mercure 演示密钥是 !ChangeMe! - 不应在生产中使用)。其负载必须至少包含以下结构才能获得发布权限

{
    "mercure": {
        "publish": []
    }
}

由于数组为空,应用程序将仅被授权发布公开更新(有关更多信息,请参阅 授权 部分)。

提示:jwt.io 网站是创建和签名 JWT 的便捷方式。查看此 示例 JWT,该 JWT 授予所有目标发布权限(注意数组中的星号)。不要忘记在表单右侧面板的底部正确设置您的密钥!

当您想向 Mercure 中心发布更新时,只需调用

\Yii::$app->mercure->publish($update);

其中 $update\bizley\yii2\mercure\Update 类的实例。例如

\Yii::$app->mercure->publish(
    new \bizley\yii2\mercure\Update(
        'http://example.com/books/1',
        \yii\helpers\Json::encode(['status' => 'OutOfStock'])
    )
);

传递给Update构造函数的第一个参数是要更新的主题。这个主题应该是一个IRI(国际资源标识符,RFC 3987):正在派发的资源的唯一标识符。

通常,此参数包含传递给客户端的资源原始URL,但它可以是任何有效的IRI,不必是存在的URL(类似于XML命名空间)。

构造函数的第二个参数是更新的内容。它可以包含任何内容,存储在任何格式中。但是,建议将资源序列化为JSON-LD、Atom、HTML或XML等超媒体格式。

使用JavaScript订阅客户端

const eventSource = new EventSource(
    'https://:3000/hub?topic=' + encodeURIComponent('http://example.com/books/1')
);
eventSource.onmessage = event => {
    // Will be called every time an update is published by the server
    console.log(JSON.parse(event.data));
}

Mercure还允许订阅多个主题,并使用URI模板作为模式

// URL is a built-in JavaScript class to manipulate URLs
const url = new URL('https://:3000/hub');
url.searchParams.append('topic', 'http://example.com/books/1');
// Subscribe to updates of several Book resources
url.searchParams.append('topic', 'http://example.com/books/2');
// All Review resources will match this pattern
url.searchParams.append('topic', 'http://example.com/reviews/{id}');

const eventSource = new EventSource(url);
eventSource.onmessage = event => {
    console.log(JSON.parse(event.data));
}

发现

Mercure协议自带发现机制。要利用它,应用程序必须在Link HTTP头中公开Mercure Hub的URL。

namespace app\controllers;

use yii\web\Controller;

class BookController extends Controller
{
    public function actionView($id)
    {
        $hubUrl = 'https://:3000/hub';

        $response = $this->asJson([
            '@id' => '/books/' . $id,
            'availability' => 'https://schema.org/InStock',
        ]);
        $response->getHeaders()->set('Link', "<$hubUrl>; rel=mercure");
        
        return $response;
    }
}

然后,客户端可以解析此头以找到Hub的URL,并对其进行订阅

// Fetch the original resource served by the web API
fetch('/books/1') // Has Link: <https://:3000/hub>; rel=mercure
    .then(response => {
        // Extract the hub URL from the Link header
        const hubUrl = response.headers.get('Link').match(/<([^>]+)>;\s+rel=(?:mercure|"[^"]*mercure[^"]*")/)[1];

        // Append the topic(s) to subscribe as query parameter
        const hub = new URL(hubUrl);
        hub.searchParams.append('topic', 'http://example.com/books/{id}');

        // Subscribe to updates
        const eventSource = new EventSource(hub);
        eventSource.onmessage = event => console.log(event.data);
    });

授权

Mercure还允许仅向授权客户端派发更新。为此,将允许接收更新的目标列表设置为Update构造函数的第三个参数

\Yii::$app->mercure->publish(
    new \bizley\yii2\mercure\Update(
        'http://example.com/books/1',
        \yii\helpers\Json::encode(['status' => 'OutOfStock']),
        ['http://example.com/user/kevin', 'http://example.com/groups/admin'] // Here are the targets
    )
);

发布者的JWT必须包含所有这些目标或在mercure.publish中使用*,否则您将收到401。
订阅者的JWT必须包含这些目标中的一个或*mercure.subscribe中以接收更新。

要订阅私人更新,订阅者必须提供一个包含至少一个目标以标记更新到Hub的JWT。

要提供此JWT,订阅者可以使用cookie或Authorization HTTP头。当浏览器打开EventSource连接时,浏览器会自动发送cookie。当客户端是浏览器时,这是最安全和首选的方法。如果客户端不是浏览器,则使用授权头是最佳选择。

在以下示例控制器中,生成的cookie包含一个JWT,该JWT本身包含适当的目标。当浏览器连接到Hub时,浏览器会自动发送此cookie。然后,Hub将验证提供的JWT的有效性,并从中提取目标。

要生成JWT,我们将使用bizley/jwt,这是一个带有lcobucci/jwt库的Yii 2组件。安装它

composer require bizley/jwt

并配置

'components' => [
    'jwt' => [
        'class' => \bizley\jwt\Jwt::class,
        'key' => '!ChangeMe!' // default Mercure demo key not to be used on production
    ],
],

现在控制器

namespace app\controllers;

use bizley\jwt\JWT;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Yii;
use yii\web\Controller;
use yii\web\Cookie;
    
class BookController extends Controller
{
    public function actionView($id)
    {
        $hubUrl = 'https://:3000/hub';
        
        $username = Yii::$app->user->name; // Retrieve the username of the current user
        
        $token = Yii::$app->jwt->getBuilder()
            // set other appropriate JWT claims, such as an expiration date
            ->set(
                'mercure',
                ['subscribe' => ["http://example.com/user/$username"]]
                // could also include the security roles, or anything else
            )
            ->sign(new Sha256(), Yii::$app->jwt->key)
            ->getToken();
                
        $response = $this->asJson([
            '@id' => '/books/' . $id,
            'availability' => 'https://schema.org/InStock',
        ]);
        $response->getHeaders()->set('Link', "<$hubUrl>; rel=mercure");
        $response->cookies->add(new Cookie([
            'name' => 'mercureAuthorization',
            'value' => $token,
            'path' => '/hub',
            'secure' => true,
            'sameSite' => Cookie::SAME_SITE_STRICT, // from PHP 7.3 and Yii 2.0.21
        ]));
        
        return $response;
    }
}

注意:要使用cookie身份验证方法,应用程序和Hub必须来自同一个域名(可以是不同的子域名)。

本文档的一些部分是从Symfony的“使用Mercure协议向客户端推送数据”页面复制的。