2017-08-22 49 views
1

我想通过为VerneMQ实现我自己的webhook来获得ACL行为。我为此使用expressapicache节点程序包。我希望代码对非JavaScript程序员也有意义。为VerneMQ使用webhooks实现ACL

在我vernemq.conf我已经建立了我的钩,他们得到正确调用:

$ vmq-admin webhooks show 
+-----------------+------------------------------+-------------+ 
|  hook  |   endpoint   |base64payload| 
+-----------------+------------------------------+-------------+ 
|auth_on_subscribe|http://127.0.0.1:3000/vmq/sub | true  | 
|auth_on_register |http://127.0.0.1:3000/vmq/auth| true  | 
| auth_on_publish |http://127.0.0.1:3000/vmq/pub | true  | 
+-----------------+------------------------------+-------------+ 

而且我禁用了所有其他插件和残疾匿名登录。在express

我的网络挂接实现(简体):

const express = require('express'); 
const apicache = require('apicache'); 
const bodyparser = require('body-parser'); 

// short cache times for demonstration 
const authcache = apicache.middleware('15 seconds'); 
const pubcache = apicache.middleware('5 seconds'); 
const subcache = apicache.middleware('10 seconds'); 

const app = express(); 

const jsonparser = bodyparser.json(); 

app.use((req, res, next) => { 
    console.log(`${req.connection.remoteAddress}:${req.connection.remotePort} ${req.method} ${req.path}`); 
    return next(); 
}); 

app.post('/vmq/auth', authcache, (req, res) => { 
    return res.status(200).json({result: 'ok'}); 
}); 

app.post('/vmq/pub', pubcache, jsonparser, (req, res) => { 
    // this gets ignored most of the time because of caching 
    if (req.body.topic === 'only/allowed/topic') { 
     return res.status(200).json({result: 'ok'}); 
    } 
    return res.status(401).end(); 
}); 

app.post('/vmq/sub', subcache, (req, res) => { 
    return res.status(200).json({result: 'ok'}); 
}); 

app.use((req, res, next) => { 
    return res.status(404).end(); 
}); 

app.use((err, res, req, next) => { 
    console.error(err); 
    return res.status(500).end(); 
}); 

const server = app.listen(3000, 'localhost',() => { 
    const address = server.address(); 
    return console.log(`listening on ${address.address}:${address.port} ...`); 
}); 

使用mqtt.js我写了一个客户端(简体):

const mqtt = require('mqtt'); 

const client = mqtt.connect('mqtt://localhost'); 

client.on('connect',() => { 
    setInterval(() => { 
     client.publish('only/allowed/topic', 'working'); 
     client.publish('some/disallowed/topic', 'working too :('); 
    }, 500); 
    return client.subscribe('some/disallowed/topic'); 
}); 

client.on('message', (topic, message) => { 
    return console.log(`${topic}:${message}`); 
}); 

什么情况是,客户端成功进行身份验证,然后发布到only/allowed/topic ,VerneMQ允许并缓存成功。但是,由于现在缓存了对/vmq/pub的成功调用,因此发布到some/disallowed/topic也适用。如果我改变发布的顺序,两者都会失败。

我会期待VerneMQ将缓存的结果映射到呼叫中的所有参数,当然有效负载除外,而不仅仅是客户端连接。但事实并非如此。 使用缓存时通过webhooks实现ACL的可能方式是什么?不使用缓存是不可能的,因为这会导致我的性能下降,并且文档建议缓存。

此外,将有人与1500+代表如此好,并创建标签vernemq? :)

回答

1

我误解了apicache如何工作,它实际上做了什么。正如VerneMQ文档中所述,我只需要设置适当的缓存标题即可。显然apicache存储实际结果并返回,无论客户实际请求什么,只要在指定的时间范围内询问即可。

这是现在的工作代码:

const express = require('express'); 
const bodyparser = require('body-parser'); 

const app = express(); 

// short cache times for demonstration (in seconds) 
const authcachetime = 15; 
const pubcachetime = 5; 
const subcachetime = 10; 

const jsonparser = bodyparser.json(); 

app.use((req, res, next) => { 
    console.log(`${req.connection.remoteAddress}:${req.connection.remotePort} ${req.method} ${req.path}`); 
    return next(); 
}); 

app.post('/vmq/auth', (req, res) => { 
    res.set('cache-control', `max-age=${authcachetime}`); 
    return res.status(200).json({result: 'ok'}); 
}); 

app.post('/vmq/pub', jsonparser, (req, res) => { 
    res.set('cache-control', `max-age=${pubcachetime}`); 
    if (req.body.topic === 'only/allowed/topic') { 
     return res.status(200).json({result: 'ok'}); 
    } 
    return res.status(401).end(); 
}); 

app.post('/vmq/sub', (req, res) => { 
    res.set('cache-control', `max-age=${subcachetime}`); 
    return res.status(200).json({result: 'ok'}); 
}); 

app.use((req, res, next) => { 
    return res.status(404).end(); 
}); 

app.use((err, res, req, next) => { 
    console.error(err); 
    return res.status(500).end(); 
}); 

const server = app.listen(3000, 'localhost',() => { 
    const address = server.address(); 
    return console.log(`listening on ${address.address}:${address.port} ...`); 
}); 

当它试图将发布到一个非法的话题预期客户端现在得到一个错误。