我正在构建一个聊天仪表板和小部件,客户应该可以将小部件放入他们的页面。一些类似的例子是Intercom或Drift。
目前,“main”应用程序是用Meteor.js编写的(它的前端是React)。我编写了一个<Widget />
组件并将其抛入/widget
目录。在这个目录中,我还有一个index.jsx
文件,它只包含以下内容:
import React from 'react';
import ......
ReactDOM.render(
<Widget/>,
document.getElementById('widget-target')
);
然后我在index.jsx
设置一个入口点的webpack配置,当运行webpack时,在公共目录中吐出bundle.js
。
只需添加script
和div
即可将其包含在其他网页上:
<script src="http://localhost:3000/bundle.js" type="text/javascript"></script>
<div id="widget-target"></div>
几个问题:
答案 0 :(得分:7)
1这个实现有什么问题?他们的安全问题是否需要注意?之前链接的两个示例似乎都以一种或另一种形式使用iframe。
正如@JeremyK所说,你在iFrame中更安全。话虽如此,许多第三方(Facebook,GA,......)正在使用中间路线,包括对讲机:
例如,对讲机要求客户在其网页上添加一些脚本:https://developers.intercom.com/docs/single-page-app#section-step-1-include-intercom-js-library非常小(https://js.intercomcdn.com/shim.d97a38b5.js)。这会加载额外的代码来设置iFrame并公开their API,这样可以轻松与iFrame进行交互,例如关闭它,设置用户属性等。
2与主流星应用程序通信的最佳方式是什么? REST API?用Socket.io发出事件?小部件是一个聊天小部件,所以我需要来回发送消息。
您有三个选择:
socket.io
而不是传统的REST API。当然,你可以混合使用socket.io
,将在整个流星上做一些额外的工作。3如何为用户和小部件实现某种唯一标识符/用户身份验证?
此部分可能应该在客户网站上进行一些工作(在您的iframe中),以便您可以在其页面上设置Cookie,并将该数据发送到您将与您的服务器通信的iframe并识别用户。您使用artwells:accounts-guest
(基于meteor:accounts-base
的那个)将取决于您决定将Iteor包含在您的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
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
});
};
答案 1 :(得分:2)
要求您的客户嵌入这样的代码并不遵循Security by Design的原则。
从他们的角度来看,您要求他们将您的预先绑定的代码嵌入到他们的网站中,使他们的网站暴露于您的代码中存在的任何隐藏的安全风险(无意或故意恶意),这些风险将无限制地访问其网站DOM,localstorage等。
这就是为什么使用iframe
是在网站中嵌入第三方内容的首选方法,因为该内容是从其余主机站点沙箱化的。
此外,遵循“最低权限”的安全原则,他们(使用您的指导/示例)可以在iframe上设置sandbox
属性,并通过白名单明确锁定小部件将拥有的权限。
在iframe
中加载小部件还可以让您更灵活地与服务器进行通信。这可能是一个普通的流星客户端,使用meteor的ddp与您的服务器进行通信。您的其他建议也是可能的。
用户身份验证/识别取决于系统的详细信息。这可能包括使用Meteor Accounts,它会为您提供密码或社交身份验证解决方案。或者您可以尝试匿名帐户解决方案,例如artwells:accounts-guest。