本指南将引导您在处理敏感医疗数据的多租户 Node.js 应用中实现搜索功能。
什么是多租户架构?
在 Meilisearch 中,您可能会有一个索引包含属于多个独立租户的数据。这种情况下,租户必须只能搜索他们自己的文档。您可以使用租户令牌来实现这一功能。
环境要求
数据模型
本指南使用一个简单的数据模型来表示医疗预约。Meilisearch 索引中的文档将如下所示:
[
{
"id": 1,
"patient": "John",
"details": "我觉得我感冒了,能帮帮我吗?",
"status": "pending"
},
{
"id": 2,
"patient": "Zia",
"details": "我正在发烧,需要尽快预约。",
"status": "pending"
},
{
"id": 3,
"patient": "Kevin",
"details": "Kevin 分享的一些机密信息。",
"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', // 您的 Meilisearch 主机地址
apiKey: apiKey
})
export function createTenantToken(patientName) {
const searchRules = {
'filter': `patient = ${patientName}`
}
}
const tenantToken = client.generateTenantToken(
apiKeyUid,
searchRules,
{
expiresAt: new Date('2030-01-01'), // 设置过期日期
apiKey: apiKey,
}
)
return tenantToken
}
当 Meilisearch 收到带有租户令牌的搜索查询时,它会解码令牌并将搜索规则应用于搜索请求。在本例中,结果会通过 patient
字段进行过滤,这意味着患者只能搜索自己的预约记录。
使用租户令牌
现在您已经拥有租户令牌,可以将其用于执行搜索。为此需要:
- 在服务端:创建端点将令牌发送至前端
- 在客户端:获取令牌并使用它执行搜索
提供租户令牌
本指南使用 Express.js 创建服务器。您可以通过以下命令安装 express
:
# 使用 NPM
npm i express
# 使用 Yarn
yarn add express
使用 pnpm
pnpm add express
然后在 `server.js` 文件中添加以下代码:
```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('服务器运行在 3000 端口')
})
这段代码创建了一个位于 http://localhost: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="https://cdn.jsdelivr.net/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="https://cdn.jsdelivr.net/npm/@meilisearch/instant-meilisearch/dist/instant-meilisearch.umd.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/instantsearch.js@4"></script>
<script>
document.addEventListener('DOMContentLoaded', async () => {
const patientId = 1 // 替换为实际患者ID
const response = await fetch(`http://localhost: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 应用中实现安全的多租户搜索功能。你创建了一个端点来为每个用户生成租户令牌(tenant token),并使用 InstantSearch 构建了一个搜索界面,通过租户令牌执行搜索操作。
本指南中的所有代码都来自我们的多租户示例应用。完整代码可在 GitHub 上获取。