Der Benutzer (Administrator) hat die Möglichkeit, die Art und Weise zu ändern, wie Ereignisse im zu abonnierenden QR-Code-Wartungssystem organisiert werden (in der Systeminstallation am Empfänger-Webhook).
Um eine neue Veranstaltung zu abonnieren, müssen folgende Daten im Formular definiert werden:
- Art der Veranstaltung
- Link mit Client-API-Adresse
- Abonnementname (optional)
- Geheimnis – eine Zeichenfolge, die zur Sicherung der Kommunikation zwischen dem QRmaint-System und der Client-Server-Anwendung verwendet wird. Seine Verabreichung wird empfohlen.
Jedes hinzugefügte Abonnement kann deaktiviert, bearbeitet oder gelöscht werden. Zusätzlich ist es möglich, ein Test-Webhook-Ereignis zu generieren, mit dem Sie ein reales Ereignis des ausgewählten Typs simulieren können, aber fiktive Testparameterwerte senden (z. B. eine fiktive Aufgaben-ID). Dies sollte die Konfiguration Ihrer Client-Server-Anwendung für die Verarbeitung von QRmaint-Webhooks erleichtern.
Derselbe Ereignistyp kann mehrmals abonniert werden, wodurch Clients mehrere Szenarien für die Handhabung eines Ereignisses im QRmaint-System erstellen können.
Für jedes abonnierte Ereignis gibt es außerdem einen Anrufverlauf und dessen Status. Der Status enthält Informationen darüber, ob das Ereignis von der Client-Server-Anwendung korrekt registriert wurde. Das TEST-Tag kennzeichnet ein Testereignis. Der Verlauf umfasst auch die eindeutige Ereignis-ID, den Textkörper und die Uhrzeit der Ereignisaufzeichnung.
Zusätzliche Informationen für Entwickler #
Die Kommunikation von QRmaint Webhooks mit der externen API erfolgt gemäß den aktuellen Kommunikationsstandards des HTTP-Protokolls. QRmaint Webhook-HTTP-Anfragen werden mit der POST-Methode gesendet .
HTTP-Anfragen enthalten Inhalte (Textkörper) in der folgenden Form: und Felder, abhängig vom Kontext (Webhook-Ereignistyp). Beispiel für einen Abfragetext, der durch ein Ereignis zur Statusänderung einer Aufgabe generiert wird:
{
string EventTypeId,
string RequestId
}
{
int WorkId,
int? PreviousStatusId,
int? NewStatusId
}
{
"EventTypeId": "WORK_STATUS_CHANGED",
"WorkId": 1371172,
"PreviousStatusId": 690,
"NewStatusId": 691,
"RequestId": "d8f2be95-55b6-4578-9c09-a085b02201aa"
}
Sicherheit und Geheimhaltung #
Der Abfrageinhalt wird mit dem HMAC SHA256-Algorithmus (Hash Message Authentication Code) gehasht , wobei eine Zeichenfolge verwendet wird – das Geheimnis. Das Geheimnis wird in der Hashing-Funktion auf der QRmaint-Systemseite verwendet, muss aber auch auf der Client-Anwendungsseite gespeichert werden, um die Richtigkeit der empfangenen Abfrage lesen zu können. Jedes Ereignisabonnement sollte ein anderes Geheimnis haben.
Das QRmaint-System verwendet das Geheimnis und den HTTP-Anforderungstext (als Zeichenfolge), um einen Hash zu erstellen, der im Header „x-qrmaint-signature“ gesendet wird. Die Client-Server-Anwendung sollte den Abfrageheader lesen und dann mithilfe des HMAC SHA256 -Algorithmus sowie des Abfragegeheimnisses und -texts überprüfen, ob der aus dem Header gelesene Wert mit dem mit dem genannten Algorithmus erstellten Hash übereinstimmt. Wenn die Werte gleich sind, bedeutet dies, dass die empfangenen Daten vom QRmaint-System gesendet wurden und nicht beispielsweise von einem Server, der sich als QRmaint ausgibt.
Beispiel einer Funktion, die die Glaubwürdigkeit von Abfragedaten aus einem Webhook-Ereignis in JavaScript (node.js) überprüft
function checkHMAC(requestSignature, body, secret) {
const hash = crypto.createHmac('SHA256', secret).update(body).digest('hex');
if (requestSignature == hash) {
console.log('request signature match');
return true;
} else {
console.log('request signature not match');
return false;
}
}
Beispiel eines einfachen HTTP-Servers in Node.js, der Anfragen mit QRmaint-Webhooks verarbeiten kann:
const express = require('express');
const crypto = require('crypto');
const https = require('https');
const fs = require('fs');
const path = require('path');
const app = express();
const port = 4000;
const secret = '1234567890';
const bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
const options = {
key: fs.readFileSync(path.join(__dirname, './certs/key.pem')),
cert: fs.readFileSync(path.join(__dirname, './certs/cert.pem'))
}
const sslServer = https.createServer(options, app);
function checkHMAC(requestSignature, body, secret) {
const hash = crypto.createHmac('SHA256', secret).update(body).digest('hex');
if (requestSignature == hash) {
console.log('request signature match');
return true;
} else {
console.log('request signature not match');
return false;
}
}
app.post('/webhook-test/new-work-request', (req, res) => {
const body = req.body;
const headers = req.headers;
const requestSignature = headers['x-qrmaint-signature'];
if (checkHMAC(requestSignature, JSON.stringify(body), secret)) {
res.status(201).json({success: true, data: {}});
} else {
res.status(401).json({success: false, data: {}});
}
});
app.post('/webhook-test/new-work-order', (req, res) => {
const body = req.body;
const headers = req.headers;
const requestSignature = headers['x-qrmaint-signature'];
if (checkHMAC(requestSignature, JSON.stringify(body), secret)) {
res.status(201).json({success: true, data: {}});
} else {
res.status(401).json({success: false, data: {}});
}
});
app.post('/webhook-test/work-status-changed', (req, res) => {
const body = req.body;
const headers = req.headers;
const requestSignature = headers['x-qrmaint-signature'];
if (checkHMAC(requestSignature, JSON.stringify(body), secret)) {
res.status(201).json({success: true, data: {}});
} else {
res.status(401).json({success: false, data: {}});
}
});
sslServer.listen(port, () => {
console.log(`Secure server is listening on port ${port}`);
});