Azure Functions 的 Azure Web PubSub 输入绑定

扩展提供两个输入绑定,以满足不同的需求。

  • WebPubSubConnection

    客户端在连接到 Azure Web PubSub 服务之前,必须知道服务终结点 URL 和有效的访问令牌。 WebPubSubConnection 输入绑定会生成所需信息,因此客户端无需自行处理令牌生成。 令牌受时间限制,可以对特定用户进行连接身份验证。 因此,不要缓存令牌或在客户端之间共享令牌。 客户端可以使用处理此输入绑定的 HTTP 触发器来检索连接信息。

  • WebPubSubContext

    使用静态 Web 应用时, HttpTrigger 是唯一受支持的触发器。 在 Web PubSub 方案中, WebPubSubContext 输入绑定可帮助用户在 Web PubSub 协议下反序列化来自服务的上游 HTTP 请求。 因此,客户可获得与 WebPubSubTrigger 相似的结果,从而在函数中轻松处理。 使用 HttpTrigger 时,客户需要在事件处理程序相应地配置 HttpTrigger 的公开 URL。

WebPubSubConnection

Example

以下示例演示了一个 HTTP 触发器函数,该函数使用输入绑定获取 Web PubSub 连接信息,并通过 HTTP 返回它。 在下面的示例中,通过 UserId 客户端请求查询部分传入,例如 ?userid={User-A}。

[Function("WebPubSubConnectionInputBinding")]
public static HttpResponseData Run([HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequestData req,
[WebPubSubConnectionInput(Hub = "<hub>", , UserId = "{query.userid}", Connection = "<web_pubsub_connection_name>")] WebPubSubConnection connectionInfo)
{
    var response = req.CreateResponse(HttpStatusCode.OK);
    response.WriteAsJsonAsync(connectionInfo);
    return response;
}
const { app, input } = require('@azure/functions');

const connection = input.generic({
    type: 'webPubSubConnection',
    name: 'connection',
    userId: '{query.userId}',
    hub: '<hub>'
});

app.http('negotiate', {
    methods: ['GET', 'POST'],
    authLevel: 'anonymous',
    extraInputs: [connection],
    handler: async (request, context) => {
        return { body: JSON.stringify(context.extraInputs.get('connection')) };
    },
});

创建文件夹协商并更新 negotiate/function.json并复制以下 JSON 代码。

{
  "scriptFile": "__init__.py",
  "bindings": [
    {
      "authLevel": "anonymous",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req"
    },
    {
      "type": "http",
      "direction": "out",
      "name": "$return"
    },
    {
      "type": "webPubSubConnection",
      "name": "connection",
      "userId": "{query.userid}",
      "hub": "<hub>",
      "direction": "in"
    }
  ]
}

在 negotiate/init 中定义函数.py。

import logging

import azure.functions as func

def main(req: func.HttpRequest, connection) -> func.HttpResponse:
    return func.HttpResponse(connection)

注释

此语言的完整示例挂起

注释

尚不支持适用于 Java 的 Web PubSub 扩展。

获取经过身份验证的用户 ID

如果此函数由经过身份验证的客户端触发,则可向生成的令牌添加用户 ID 声明。 可以轻松地使用应用服务身份验证向函数应用添加身份验证。

应用服务身份验证会设置名为 x-ms-client-principal-id 和 x-ms-client-principal-name(分别包含经身份验证的用户的客户端主体 ID 和名称)的 HTTP 标头。

可以使用绑定表达式将绑定的属性设置为 UserId 任一标头中的值: {headers.x-ms-client-principal-id} 或 {headers.x-ms-client-principal-name}。

[Function("WebPubSubConnectionInputBinding")]
public static HttpResponseData Run([HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequestData req,
[WebPubSubConnectionInput(Hub = "<hub>", , UserId = "{headers.x-ms-client-principal-id}", Connection = "<web_pubsub_connection_name>")] WebPubSubConnection connectionInfo)
{
    var response = req.CreateResponse(HttpStatusCode.OK);
    response.WriteAsJsonAsync(connectionInfo);
    return response;
}
const { app, input } = require('@azure/functions');

const connection = input.generic({
    type: 'webPubSubConnection',
    name: 'connection',
    userId: '{headers.x-ms-client-principal-id}',
    hub: '<hub>'
});

app.http('negotiate', {
    methods: ['GET', 'POST'],
    authLevel: 'anonymous',
    extraInputs: [connection],
    handler: async (request, context) => {
        return { body: JSON.stringify(context.extraInputs.get('connection')) };
    },
});

创建文件夹协商并更新 negotiate/function.json并复制以下 JSON 代码。

{
  "scriptFile": "__init__.py",
  "bindings": [
    {
      "authLevel": "anonymous",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req"
    },
    {
      "type": "http",
      "direction": "out",
      "name": "$return"
    },
    {
      "type": "webPubSubConnection",
      "name": "connection",
      "userId": "{headers.x-ms-client-principal-id}",
      "hub": "<hub>",
      "direction": "in"
    }
  ]
}

在 negotiate/init 中定义函数.py。

import logging

import azure.functions as func

def main(req: func.HttpRequest, connection) -> func.HttpResponse:
    return func.HttpResponse(connection)

注释

此语言的完整示例挂起

注释

尚不支持适用于 Java 的 Web PubSub 扩展。

配置

下表解释了在 function.json 文件和 WebPubSubConnection 特性中设置的绑定配置属性。

function.json 属性 Attribute 属性 Description
type n/a 必须设置为 webPubSubConnection
direction n/a 必须设置为 in
name n/a 变量名称,在输入连接绑定对象的函数代码中使用。
集线器 集线器 必需 - 该值必须设置为 Web PubSub Hub 的名称,以触发函数。 支持在特性中将该值设置为更高优先级,或者在应用设置中将该值设置为全局值。
userId UserId 可选 - 用户标识符声明的值,将在访问密钥令牌中设置。
clientProtocol ClientProtocol 可选 - 客户端协议类型。 有效值包括 default 和 mqtt。
对于 MQTT 客户端,必须将它设置为 mqtt.
对于其他客户端,可以省略属性或将其设置为 default。
连接 连接 必需 - 应用设置的名称,包含 Web PubSub 服务连接字符串(默认为“WebPubSubConnectionString”)。

使用情况

WebPubSubConnection 提供以下属性。

绑定名称 绑定类型 Description
BaseUri Uri Web PubSub 客户端连接 URI。
Uri Uri Web PubSub 连接的绝对 URI,包含根据请求生成的 AccessToken。
AccessToken 字符串 根据请求的用户ID和服务信息生成的AccessToken。

WebPubSubConnection 提供以下属性。

绑定名称 Description
baseUrl Web PubSub 客户端连接 URI。
url Web PubSub 连接的绝对 URI,包含根据请求生成的 AccessToken。
accessToken 根据请求的用户ID和服务信息生成的AccessToken。

注释

尚不支持适用于 Java 的 Web PubSub 扩展。

对生成的令牌进行更多自定义

仅限于绑定参数类型不支持传递列表或数组,这意味着WebPubSubConnection并不完全支持服务器 SDK 的所有参数,尤其是roles,并且还包括groups和expiresAfter。

当客户需要在函数中添加角色或延迟生成访问令牌时,建议使用 适用于 C# 的服务器 SDK。

[Function("WebPubSubConnectionCustomRoles")]
public static HttpResponseData Run([HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequestData req)
{
    var serviceClient = new WebPubSubServiceClient(new Uri(endpoint), "<hub>", "<web-pubsub-connection-string>");
    var userId = req.Query["userid"].FirstOrDefault();
    // your method to get custom roles.
    var roles = GetRoles(userId);
    var url = await serviceClient.GetClientAccessUriAsync(TimeSpan.FromMinutes(5), userId, roles);
    var response = req.CreateResponse(HttpStatusCode.OK);
    response.WriteString(url.ToString());
    return response;
}

当客户需要在函数中添加角色或延迟生成访问令牌时,建议使用 适用于 JavaScript 的服务器 SDK。

const { app } = require('@azure/functions');
const { WebPubSubServiceClient } = require('@azure/web-pubsub');
app.http('negotiate', {
    methods: ['GET', 'POST'],
    authLevel: 'anonymous',
    handler: async (request, context) => {
        const serviceClient = new WebPubSubServiceClient(process.env.WebPubSubConnectionString, "<hub>");
        let token = await serviceClient.getAuthenticationToken({ userId: req.query.userid, roles: ["webpubsub.joinLeaveGroup", "webpubsub.sendToGroup"] });
        return { body: token.url };
    },
});

注释

此语言的完整示例挂起

注释

尚不支持适用于 Java 的 Web PubSub 扩展。

WebPubSubContext

Example

// validate method when upstream set as http://<func-host>/api/{event}
[Function("validate")]
public static HttpResponseData Validate(
    [HttpTrigger(AuthorizationLevel.Anonymous, "options")] HttpRequestData req,
    [WebPubSubContextInput] WebPubSubContext wpsReq)
{
    return BuildHttpResponseData(req, wpsReq.Response);
}

// Respond AbuseProtection to put header correctly.
private static HttpResponseData BuildHttpResponseData(HttpRequestData request, SimpleResponse wpsResponse)
{
    var response = request.CreateResponse();
    response.StatusCode = (HttpStatusCode)wpsResponse.Status;
    response.Body = response.Body;
    foreach (var header in wpsResponse.Headers)
    {
        response.Headers.Add(header.Key, header.Value);
    }
    return response;
}
const { app, input } = require('@azure/functions');

const wpsContext = input.generic({
    type: 'webPubSubContext',
    name: 'wpsContext'
});

app.http('connect', {
    methods: ['GET', 'POST'],
    authLevel: 'anonymous',
    extraInputs: [wpsContext],
    handler: async (request, context) => {
        var wpsRequest = context.extraInputs.get('wpsContext');

        return { "userId": wpsRequest.request.connectionContext.userId };
    }
});

注释

此语言的完整示例挂起

注释

尚不支持适用于 Java 的 Web PubSub 扩展。

配置

下表解释了在 functions.json 文件和 WebPubSubContext 特性中设置的绑定配置属性。

function.json 属性 Attribute 属性 Description
type n/a 必须设置为 webPubSubContext。
direction n/a 必须设置为 in。
name n/a 在函数代码中使用的变量名称,用于输入 Web PubSub 请求。
connections 连接 可选 - 应用设置名称或设置集合前缀的数组,用于标识上游Azure Web PubSub服务连接。 这些值用于滥用保护和签名验证。 如果未指定,请回退到全局 WebPubSubConnectionString 应用设置。 如果未配置验证,则会跳过验证并接受所有请求。
例子: ["CustomWebPubSubConnection1", "CustomWebPubSubConnection2"]

Important

为了获得最佳安全性,函数应用在连接到 Web PubSub 服务时应使用托管标识,而不是使用包含共享密钥的连接字符串。 有关详细信息,请参阅 使用 Microsoft Entra ID 授权托管标识请求。

使用情况

WebPubSubContext 提供以下属性。

绑定名称 绑定类型 Description 属性
申请 WebPubSubEventRequest 从客户端请求,有关详细信息,请参阅下表。 请求标头中的 WebPubSubConnectionContext 和从请求正文反序列化的其他属性用于描述请求,例如 Reason 的 DisconnectedEventRequest。
响应 HttpResponseMessage 扩展生成响应,主要针对 AbuseProtection 和错误情况。 -
errorMessage 字符串 描述处理上游请求时的错误详细信息。 -
有错误 bool 指示其是否是有效 Web PubSub 上游请求的标志。 -
isPreflight bool 指示其是否是 AbuseProtection 的预检请求的标志。 -

对于 WebPubSubEventRequest,会将其反序列化为不同的类,从而提供关于请求场景的不同信息。 对于 PreflightRequest 或无效的情况,用户可以检查标志 IsPreflight 和 HasError 来了解情况。 我们建议你直接返回系统生成响应 WebPubSubContext.Response ,或者客户可以按需记录错误。 在不同方案中,客户可以按如下所示读取请求属性。

派生类 Description 属性
PreflightRequest 当 AbuseProtection 为 IsPreflight 时,在 中使用 -
ConnectEventRequest 在系统 Connect 事件类型中使用 权利声明、查询、子协议、客户证书
ConnectedEventRequest 在系统 Connected 事件类型中使用 -
UserEventRequest 在用户事件类型中使用 数据 (Data)、数据类型 (DataType)
DisconnectedEventRequest 在系统 Disconnected 事件类型中使用 原因

注释

WebPubSubContext尽管这是一个输入绑定,但在HttpTrigger比较中WebPubSubTrigger提供了类似的请求反序列化方式,但存在限制,即不支持合并后的连接状态。 服务端仍然会遵守返回响应,但用户需要自己构建响应。 如果用户需要设置事件响应,应返回一个包含 或用户事件消息的 作为响应体,并在响应头中使用键 设置连接状态。