1 这个实现有什么问题?他们有什么安全问题需要注意吗?前面链接的两个示例似乎都以一种或另一种形式使用了 iframe。
正如 @JeremyK 提到的,在 iFrame 中你会更安全。话虽如此,许多第三方(Facebook、GA 等)都在使用中间路线,包括 Intercom:
- 要求用户将您的捆绑代码集成到他们的网页中。然后,您需要确保不会在他们的网站上引入安全漏洞。这段代码将做两件事:
- 负责设置一个 iframe,您的服务的主要部分将在其中发生。您可以对其进行定位、设置样式等。这可以确保 iframe 中发生的所有逻辑都是安全的,并且您不会暴露。
- 使用窗口消息传递在您的客户网页和 iframe 之间公开一些 API。
- 然后,主代码(iframe 代码)由第一个脚本异步加载,并且不包含在其中。
例如,Intercom 要求客户在其页面上包含一些脚本:https://developers.intercom.com/docs/single-page-app#section-step-1-include-intercom-js-library https://developers.intercom.com/docs/single-page-app#section-step-1-include-intercom-js-library那相当小(https://js.intercomcdn.com/shim.d97a38b5.js https://js.intercomcdn.com/shim.d97a38b5.js)。这会加载设置 iFrame 并公开的额外代码他们的API https://developers.intercom.com/docs/intercom-javascript这将使与 iFrame 的交互变得容易,例如关闭它、设置用户属性等。
2 与我的主要流星应用程序通信的最佳方式是什么? REST API?使用 Socket.io 发出事件?该小部件是一个聊天小部件,因此我需要来回发送消息。
你有三个选择:
- 将您的小部件构建为整个 Meteor 应用程序。这将增加需要加载的代码的大小。作为额外代码的交换,您可以通过 Meteor API 与后端进行通信,例如流星召唤 https://docs.meteor.com/api/methods.html#Meteor-call,获取所有数据的反应性(例如,如果您通过主 Meteor 应用程序向用户发送响应,则响应将在客户端上弹出,只要它们位于同一数据库上,则无需执行任何操作(无需在同一台服务器上)),以及乐观的 UI。简而言之,您已经拥有 Meteor 提供的所有功能,并且与您现有的后端(我认为是 Meteor)集成可能会更容易。
- 不包括流星。由于您正在构建聊天应用程序,因此您可能需要
socket.io
通过传统的 REST API。当然你可以混合使用两者
- Use 流星DDP https://www.npmjs.com/package/ddp。 (它有点像 socket.io,但对于 Meteor。Meteor 应用程序使用它来处理对服务器的所有请求)这将包含比完整 Meteor 更少的内容,并且可能比 REST API 更容易集成到您的 Meteor 后端/
socket.io
,并且将对完整的 Meteor 进行一些额外的工作。
3 如何为用户和小部件实现某种唯一标识符/用户身份验证?
这部分可能应该在客户网站上(相对于您的 iframe 中)做一些工作,以便您可以在他的页面上设置 cookie,并将该数据发送到您的 iframe,该 iframe 将与您的服务器通信并识别用户。无论你使用artwells:accounts-guest
(这是基于meteor:accounts-base
) 将取决于您是否决定将 Meteor 包含在您的 iframe 中。
如果您的 iframe 中没有 Meteor,您可以执行以下操作:
.
const token = createToken();
Users.insert({ tokens: [token] });
// send the token back to your iframe
// and set is as a cookie on your customer website
- 然后对于您的服务器的每次调用,在您的 iframe 上:
.
let token;
const makeRequest = async (request) => {
token = token || getCookieFromCustomerWebsite();
// pass the token to your HTTP / socket.io / ... request.
// in the header of whatever
return await callServer(token, request);
};
.
const loginAs = (userId, cb) => {
DDP._CurrentInvocation.withValue(new DDPCommon.MethodInvocation({
isSimulation: false,
userId,
}), cb);
};
// my middleware that run on all API requests for a non Meteor client
export const identifyUserIfPossible = (req, res, next) => {
const token = req.headers.authorization;
if (!token) {
return next();
}
const user = Users.findOne({ tokens: token });
if (!user) {
return next();
}
loginAs(user._id, () => {
next();
// Now Meteor.userId() === user._id from all calls made on that request
// So you can do Meteor.call('someMethod') as you'd do on a full Meteor stack
});
};