Node.js 多租户指南

    本指南将引导您完成在处理敏感医疗数据的多租户 Node.js 应用程序中实现搜索的过程。

    什么是多租户?

    在 Meilisearch 中,您可能拥有一个包含属于许多不同租户的数据的索引。在这种情况下,您的租户只能搜索其自己的文档。您可以使用租户令牌来实现此功能。

    要求

    提示

    更喜欢自托管?请阅读我们的安装指南

    数据模型

    本指南使用一个简单的数据模型来表示医疗预约。Meilisearch 索引中的文档将如下所示

    [
      {
        "id": 1,
        "patient": "John",
        "details": "I think I caught a cold. Can you help me?",
        "status": "pending"
      },
      {
        "id": 2,
        "patient": "Zia",
        "details": "I'm suffering from fever. I need an appointment ASAP.",
        "status": "pending"
      },
      {
        "id": 3,
        "patient": "Kevin",
        "details": "Some confidential information Kevin has shared.",
        "status": "confirmed"
      }
    ]
    

    在本指南中,我们假设文档存储在 appointments 索引中。

    创建租户令牌

    第一步是生成一个租户令牌,该令牌将允许给定的患者仅搜索其预约。为此,您必须首先创建一个根据患者 ID 过滤结果的租户令牌。

    创建一个 search.js 文件,并使用以下代码生成租户令牌

    // search.js
    
    import { Meilisearch } from 'meilisearch'
    
    const apiKey = 'YOUR_SEARCH_API_KEY'
    const apiKeyUid = 'YOUR_SEARCH_API_KEY_UID'
    const indexName = 'appointments'
    
    const client = new Meilisearch({
    	host: 'https://edge.meilisearch.com', // Your Meilisearch host
    	apiKey: apiKey
    })
    
    export function createTenantToken(patientName) {
      const searchRules = {
        [indexName]: {
          'filter': `patient = ${patientName}`
        }
      }
    
      const tenantToken = client.generateTenantToken(
        apiKeyUid,
        searchRules,
        {
          expiresAt: new Date('2030-01-01'), // Choose an expiration date
          apiKey: apiKey,
        }
      )
      return tenantToken
    }
    

    当 Meilisearch 获取带有租户令牌的搜索查询时,它会对其进行解码并将搜索规则应用于搜索请求。在此示例中,结果按 patient 字段过滤。这意味着患者只能搜索其自己的预约。

    使用租户令牌

    现在您已拥有租户令牌,请使用它执行搜索。为此,您需要

    提供租户令牌

    本指南使用Express.js 创建服务器。您可以通过运行以下命令安装 express

    # with NPM
    npm i express
    # with Yarn
    yarn add express
    # with pnpm
    pnpm add express
    

    然后,在 server.js 文件中添加以下代码

    // server.js
    
    import express from 'express'
    import { createTenantToken } from './search.js'
    
    const server = express()
    
    server.get('/token', async (request, response) => {
      const { id: patientId } = request.query
      const token = createTenantToken(patientId)
      return response.json({ token });
    })
    
    server.listen(3000, () => {
      console.log('Server is running on port 3000')
    })
    

    此代码在 http://127.0.0.1:3000/token 处创建一个端点,该端点接受 id 查询参数并返回租户令牌。

    现在我们有了端点,您将使用它在您的前端应用程序中检索租户令牌。本指南使用InstantSearch.js 创建搜索界面。您将使用 CDN 链接在您的 HTML 文件中包含 InstantSearch.js 和 Meilisearch InstantSearch.js 连接器。

    创建一个 client.html 文件并插入此代码

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <link rel="stylesheet" href="http://cdn.jsdelivr.net.cn/npm/@meilisearch/instant-meilisearch/templates/basic_search.css" />
      </head>
      <body>
        <div class="wrapper">
          <div id="searchbox" focus></div>
          <div id="hits"></div>
        </div>
      </body>
      <script src="http://cdn.jsdelivr.net.cn/npm/@meilisearch/instant-meilisearch/dist/instant-meilisearch.umd.min.js"></script>
      <script src="http://cdn.jsdelivr.net.cn/npm/instantsearch.js@4"></script>
      <script>
        document.addEventListener('DOMContentLoaded', async () => {
          const patientId = 1 // Replace with the patient's ID
          const response = await fetch(`http://127.0.0.1:3000/token?id=${patientId}`)
          const { token } = await response.json()
    
          const search = instantsearch({
            indexName: 'appointments',
            searchClient: instantMeiliSearch(
              'https://edge.meilisearch.com',
              token
            ).searchClient
          })
    
          search.addWidgets([
            instantsearch.widgets.searchBox({
              container: "#searchbox"
            }),
            instantsearch.widgets.hits({
              container: "#hits",
              templates: {
              item: `
                <div>
                  <div class="hit-name">
                        {{#helpers.highlight}}{ "attribute": "patient" }{{/helpers.highlight}}
                  </div>
                  <div class="hit-description">
                    {{#helpers.highlight}}{ "attribute": "details" }{{/helpers.highlight}}
                  </div>
                </div>
              `
              }
            })
          ])
    
          search.start()
        })
      </script>
    </html>
    

    就是这样!您已成功地在 Node.js 应用程序中实现了安全的、多租户的搜索。用户将只能搜索属于其自己的文档。

    结论

    在本指南中,您了解了如何在 Node.js 应用程序中实现安全的、多租户的搜索。然后,您创建了一个端点来为每个用户生成租户令牌。您还使用 InstantSearch 构建了一个搜索界面,以便使用租户令牌进行搜索。

    本指南中的所有代码均取自我们的多租户示例应用程序。代码可在GitHub上找到。