【发布时间】:2016-08-05 09:31:50
【问题描述】:
我们正在构建一个应用程序,我们决定使用 pubnub 作为通知和聊天的传输方式。 这是要求
- 用户应该能够在他们之间直接通信,
- 只有两个正在讨论的用户才能看到对话
- 我假设发布和订阅密钥都被泄露了
- 服务器应该能够为每个用户发送通知
- 用户应该只能看到他的通知
** 在某些时候,我意识到您不能使用两组密钥发布到同一个频道 - 因为一组密钥标识了频道 - 所以服务器主密钥集和客户端无级别密钥不是一个选项**
因此,最重要的是,通过使用 pam,这是通知流程
使用密钥的服务器在全局级别撤销 pub/sub 密钥的任何权限 {读:假,写:假,管理:假} 这样,没有人可以在全局级别上使用键做任何事情
用户发送一个令牌 - 此令牌成为 authKey - 只有使用该身份验证密钥,用户才能在通知通道上只读(称为“notif-{userId}”)
现在服务器需要有某种 masterKey 可以发布到所有频道 - 所以合乎逻辑的做法是发出带有 { read: true, 的 .grant() 请求写:真,管理:真,authKey:MASTER_KEY} 这里我们失败了 - 因为它响应“仅授权授权被保留以供将来使用”
现在对于聊天,想法是创建一个频道名称“chat-{userId1}-{userId2}”并将此频道添加到组“chats-{userId1}”和“chats-{userId2}”和而不是 .grant() 基于令牌对每个用户频道的权限 - 授权成功但用户订阅频道组 - 但实际发布到组失败并出现 状态 : { 类别:“PNAccessDeniedCategory”, 操作:“PNPublishOperation” }
这里是复制问题的代码示例
'use strict';
const pubnubConf = require('../config/pubnub-master');
const PubNub = require('pubnub');
const masterKeys = pubnubConf.getMasterKeys();
const pubnub = new PubNub(masterKeys);
const pubnubSecret = new PubNub(pubnubConf.getSecretKeys());
const token = 'lklkdjwdq';
masterKeys.authKey = token;
const pubnubClient = new PubNub(masterKeys);
const userAGroup = 'chats-aaa';
const userBGroup = 'chats-bbb';
const chat = 'chat-aaa-bbb';
function _invalidateServerKeys () {
return new Promise((resolve, reject) => {
pubnubSecret.grant({
read: false,
write: false,
manage: false,
ttl: 0
}, (status, response) => {
if (status.error) {
reject(status);
}
resolve(status);
});
});
}
function _setMasterKeyForChannelGroup () {
return new Promise((resolve, reject) => {
pubnubSecret.grant({
read: true,
write: true,
manage: true,
channels: [chat],
channelGroups: [userAGroup, userBGroup],
authKeys: [pubnubConf.getMasterKey()],
ttl: 0
}, (status, response) => {
if (status.error) {
this._logger.fatal({
status: status,
response: response
});
reject(status);
}
resolve(status);
});
});
}
function _addChanelsToGroup () {
return new Promise((resolve, reject) => {
pubnub.channelGroups.addChannels({
channels: [chat],
channelGroup: [userBGroup]
}, status => {
if (status.error) {
this._logger.fatal(status);
return reject();
}
resolve(status);
});
});
}
function _addTokenPermission () {
return new Promise((resolve, reject) => {
pubnubSecret.grant({
channelGroups: [userBGroup],
authKeys: [token],
ttl: 65,
read: true,
write: true,
manage: false
}, (status, response) => {
if (status.error) {
return reject({
status: status,
response: response
});
}
resolve();
});
});
};
function _subscribeToGroup () {
return new Promise((resolve, reject) => {
pubnubClient.addListener({
status: statusEvent => {
if (statusEvent.error) {
reject(statusEvent);
return;
}
resolve(statusEvent);
},
message: message => {
}
});
pubnubClient.subscribe(
{channelGroups: [userBGroup]});
});
}
function _publishToGroup () {
pubnubClient.publish(
{
message: {
such: 'object'
},
channel: chat,
storeInHistory: false
},
function (status, response) {
if (status.error) {
// handle error
console.log(status)
} else {
console.log("message Published w/ timetoken", response.timetoken)
}
}
);
}
_invalidateServerKeys()
.then(_setMasterKeyForChannelGroup)
.then(_addChanelsToGroup)
.then(_addTokenPermission)
.then(_subscribeToGroup)
.then(_publishToGroup);
const masterAuthKey = 'qdwqqdwdqwqdwqdw';
module.exports = {
getSecretKeys: () => ({
ssl: true,
logVerbosity: true,
publishKey: 'pub-c-',
subscribeKey: 'sub-c-',
secretKey: 'sec-c-'
}),
getMasterKeys: () => ({
ssl: true,
logVerbosity: true,
publishKey: 'pub-c-',
subscribeKey: 'sub-c-',
authKey: masterAuthKey
}),
getMasterKey: () => (masterAuthKey)
};
当然,只有身份验证的 PAM 可以解决这个问题 - 但它似乎不可用 另一种方法是管理每个频道的服务器端密钥 - 但这有点浪费。
【问题讨论】: