教程:使用 Azure Functions 进行 Azure SignalR 服务身份验证
在本分步教程中,你将使用以下技术构建包含身份验证和私密消息传送功能的聊天室:
- Azure Functions:用于验证用户身份和发送聊天消息的后端 API。
- Azure SignalR 服务:用于将新消息广播到连接的聊天客户端的服务。
- Azure 存储:Azure Functions 所需的存储服务。
- Azure 应用服务:提供用户身份验证的服务。
先决条件
- 具有活动订阅的 Azure 帐户。 如果没有,可以创建一个试用帐户。
- Node.js(版本 18.x)。
- Azure Functions Core Tools(版本 4)。
在 Azure 上创建必备资源
创建 Azure SignalR 服务资源
你的应用程序将访问 Azure SignalR 服务实例。 使用以下步骤在 Azure 门户中创建 Azure SignalR 服务实例。
在 Azure 门户中,选择“创建资源”(+) 按钮。
搜索“SignalR 服务”并将其选中。
选择“创建”。
输入以下信息。
名称 值 资源组 创建具有唯一名称的新资源组。 资源名称 为 Azure SignalR 服务实例输入唯一的名称。 区域 选择附近的区域。 定价层 选择“免费”。 服务模式 选择“无服务器”。 选择“查看 + 创建” 。
选择“创建” 。
创建 Azure 函数应用和 Azure 存储帐户
在 Azure 门户的主页上,选择“创建资源”(+)。
搜索“函数应用”并选择它。
选择“创建”。
输入以下信息。
名称 值 资源组 使用你的 Azure SignalR 服务实例所在的资源组。 函数应用名称 为函数应用输入唯一的名称。 运行时堆栈 选择“Node.js”。 区域 选择附近的区域。 默认情况下,会在同一资源组中随函数应用一起创建新的 Azure 存储帐户。 如果你想要在函数应用中使用其他存储帐户,请切换到“托管”选项卡以选择一个帐户。
选择查看 + 创建,然后选择创建。
在本地创建 Azure Functions 项目
初始化函数应用
在命令行中,为项目创建一个根文件夹并切换到该文件夹。
在终端中运行以下命令,以创建新的 JavaScript Functions 项目。
func init --worker-runtime node --language javascript --name my-app
默认情况下,生成的项目包含一个 host.json 文件,其中的扩展捆绑包包含 SignalR 扩展。 有关扩展捆绑包的详细信息,请参阅注册 Azure Functions 绑定扩展。
配置应用程序设置
在本地运行和调试 Azure Functions 运行时时,函数应用将从 local.settings.json 读取应用程序设置。 使用 Azure SignalR 服务实例的连接字符串以及前面创建的存储帐户更新此文件。
将 local.settings.json 的内容替换为以下代码:
{
"IsEncrypted": false,
"Values": {
"FUNCTIONS_WORKER_RUNTIME": "node",
"AzureWebJobsStorage": "<your-storage-account-connection-string>",
"AzureSignalRConnectionString": "<your-Azure-SignalR-connection-string>"
}
}
在上述代码中:
在
AzureSignalRConnectionString
设置中输入 Azure SignalR 服务连接字符串。若要获取此字符串,请在 Azure 门户中转到你的 Azure SignalR 服务实例。 在“设置”部分,找到“密钥”设置。 选择连接字符串右侧的“复制”按钮,将连接字符串复制到剪贴板。 可以使用主要或辅助连接字符串。
在
AzureWebJobsStorage
设置中输入存储帐户连接字符串。若要获取此字符串,请在 Azure 门户中转到你的存储帐户。 在“安全 + 网络 ”部分中,找到“访问密钥”设置。 选择连接字符串右侧的“复制”按钮,将连接字符串复制到剪贴板。 可以使用主要或辅助连接字符串。
创建一个用于在 Azure SignalR 服务中验证用户身份的函数
当聊天应用在浏览器中首次打开时,需要使用有效的连接凭据连接到 Azure SignalR 服务。 在函数应用中创建一个名为 negotiate
的 HTTP 触发器函数,以返回此连接信息。
注意
此函数必须命名为 negotiate
,因为 SignalR 客户端需要以 /negotiate
结尾的终结点。
在根项目文件夹中,使用以下命令基于内置模板创建
negotiate
函数:func new --template "SignalR negotiate HTTP trigger" --name negotiate
打开 negotiate/function.json 以查看函数绑定配置。
该函数包含一个 HTTP 触发器绑定,用于接收来自 SignalR 客户端的请求。 该函数还包含一个 SignalR 输入绑定,用于生成有效的凭据,使客户端能够连接到名为
default
的 Azure SignalR 服务中心。{ "disabled": false, "bindings": [ { "authLevel": "anonymous", "type": "httpTrigger", "direction": "in", "methods": ["post"], "name": "req", "route": "negotiate" }, { "type": "http", "direction": "out", "name": "res" }, { "type": "signalRConnectionInfo", "name": "connectionInfo", "hubName": "default", "connectionStringSetting": "AzureSignalRConnectionString", "direction": "in" } ] }
对于本地开发,
signalRConnectionInfo
绑定中没有userId
属性。 稍后,在将函数应用部署到 Azure 时,你将添加该属性来设置 SignalR 连接的名称。关闭 negotiate/function.json 文件。
打开 negotiate/index.js 以查看函数的正文:
module.exports = async function (context, req, connectionInfo) { context.res.body = connectionInfo; };
此函数从输入绑定中提取 SignalR 连接信息,并在 HTTP 响应正文中将此信息返回给客户端。 SignalR 客户端使用此信息连接到 Azure SignalR 服务实例。
创建用于发送聊天消息的函数
Web 应用还需要使用一个 HTTP API 来发送聊天消息。 创建一个 HTTP 触发器函数,用于将消息发送到使用 Azure SignalR 服务的所有已连接客户端:
在根项目文件夹中,使用以下命令从模板创建名为
sendMessage
的 HTTP 触发器函数:func new --name sendMessage --template "Http trigger"
若要为函数配置绑定,请将 sendMessage/function.json 的内容替换为以下代码:
{ "disabled": false, "bindings": [ { "authLevel": "anonymous", "type": "httpTrigger", "direction": "in", "name": "req", "route": "messages", "methods": ["post"] }, { "type": "http", "direction": "out", "name": "res" }, { "type": "signalR", "name": "$return", "hubName": "default", "direction": "out" } ] }
前面的代码会对原始文件做出两项更改:
- 它将路由更改为
messages
,并将 HTTP 触发器限制为POST
HTTP 方法。 - 它添加一个 Azure SignalR 服务输出绑定,用于将函数返回的消息发送到已连接至名为
default
的 Azure SignalR 服务中心的所有客户端。
- 它将路由更改为
将 sendMessage/index.js 的内容替换为以下代码:
module.exports = async function (context, req) { const message = req.body; message.sender = (req.headers && req.headers["x-ms-client-principal-name"]) || ""; let recipientUserId = ""; if (message.recipient) { recipientUserId = message.recipient; message.isPrivate = true; } return { userId: recipientUserId, target: "newMessage", arguments: [message], }; };
此函数从 HTTP 请求中提取正文,并将其发送到连接到 Azure SignalR 服务的客户端。 它在每个客户端上调用名为
newMessage
的函数。该函数可以读取发送者的标识,并可以接受消息正文中的
recipient
值,以允许你以私密方式向单个用户发送消息。 稍后你将在本教程中使用这些功能。保存文件。
托管聊天客户端 Web 用户界面
聊天应用程序的 UI 是通过 ASP.NET Core SignalR JavaScript 客户端使用 Vue JavaScript 框架创建的简单单页应用程序 (SPA)。
在函数项目的根目录中创建名为 content 的文件夹。
在 content 文件夹中创建名为 index.html 的文件。
在根项目文件夹中,使用以下命令基于模板创建名为
index
的 HTTP 触发器函数:func new --name index --template "Http trigger"
将
index/index.js
的内容修改为以下代码:const fs = require("fs"); module.exports = async function (context, req) { const fileContent = fs.readFileSync("content/index.html", "utf8"); context.res = { // status: 200, /* Defaults to 200 */ body: fileContent, headers: { "Content-Type": "text/html", }, }; };
该函数将读取静态网页并将其返回给用户。
打开 index/function.json,将绑定的
authLevel
值更改为anonymous
。 现在,整个文件如下示例所示:{ "bindings": [ { "authLevel": "anonymous", "type": "httpTrigger", "direction": "in", "name": "req", "methods": ["get", "post"] }, { "type": "http", "direction": "out", "name": "res" } ] }
在本地测试你的应用。 使用以下命令启动函数应用:
func start
在 Web 浏览器中打开
http://localhost:7071/api/index
。 应当会出现一个聊天网页。在聊天框中输入一条消息。
选择 Enter 键后,该消息将显示在网页上。 由于未设置 SignalR 客户端的用户名,因此你将以匿名方式发送所有消息。
部署到 Azure 并启用身份验证
你目前为止一直在本地运行函数应用和聊天应用程序。 现在,将它们部署到 Azure,并启用身份验证和私密消息传送。
为函数应用配置身份验证
到目前为止,聊天应用程序以匿名方式工作。 在 Azure 中,你将使用应用服务身份验证来验证用户的身份。 将已经过身份验证的用户的用户 ID 或用户名传递给 SignalRConnectionInfo
绑定,以生成进行用户身份验证时所需的连接信息。
打开 negotiate/function.json。
将值为
{headers.x-ms-client-principal-name}
的userId
属性插入到SignalRConnectionInfo
绑定中。 此值是一个绑定表达式,用于将 SignalR 客户端的用户名设置为已经过身份验证的用户的名称。 绑定现在应如以下示例所示:{ "type": "signalRConnectionInfo", "name": "connectionInfo", "userId": "{headers.x-ms-client-principal-name}", "hubName": "default", "direction": "in" }
保存文件。
将函数应用部署到 Azure
使用以下命令将函数应用部署到 Azure:
func azure functionapp publish <your-function-app-name> --publish-local-settings
--publish-local-settings
选项将 local.settings.json 文件中的本地设置发布到 Azure,因此你无需再次在 Azure 中配置这些设置。
启用应用服务身份验证
Azure Functions 支持使用 Microsoft Entra ID 和 Microsoft 帐户进行身份验证。
在 Azure 门户中,转到你的函数应用的资源页。
选择“设置”>“身份验证”。
选择“添加标识提供者”。
从“标识提供者”列表中,选择“Microsoft”。 然后选择“添加” 。
完成的设置将创建一个应用注册,它会将你的标识提供者与你的函数应用相关联。
有关支持的标识提供者的详细信息,请参阅以下文章:
尝试运行应用程序
- 打开
https://<YOUR-FUNCTION-APP-NAME>.chinacloudsites.cn/api/index
。 - 选择“登录”,使用所选的身份验证提供程序进行身份验证。
- 在主要聊天框中输入公共消息并发送这些消息。
- 选择聊天历史记录中的用户名来发送私密消息。 只有选定的接收者可以收到这些消息。
祝贺你! 你已部署了一个实时无服务器聊天应用。
清理资源
若要清理你在本教程中创建的资源,请使用 Azure 门户删除相应的资源组。
注意
删除资源组会删除其中包含的所有资源。 如果资源组包含超出本教程范围的资源,这些资源也将被删除。
后续步骤
本教程已介绍如何将 Azure Functions 与 Azure SignalR 服务配合使用。 接下来请详细了解如何使用 Azure Functions 的 Azure SignalR 服务绑定来构建实时无服务器应用程序。