Einer der kritischsten Teile jedes Bots ist die Discord-Bot-Berechtigung-Schicht, die entscheidet, wer welchen Befehl ausführen darf. Einen ban-, kick- oder Serverkonfigurationsbefehl für alle offen zu lassen, ist eine Katastrophe mit Ansage. In diesem Artikel bauen wir mit discord.js v14 ein mehrschichtiges Berechtigungssystem: Wir stützen uns auf Discords eigenes Berechtigungsmodell und entwerfen zusätzlich eigene Abläufe, die bestimmte Rollen erfordern. Das Ziel ist, unbefugte Nutzung nicht stillschweigend, sondern mit klarer Rückmeldung an den Nutzer zu blockieren.
Wie Berechtigungen in Discord funktionieren
Es hilft, zwei verschiedene Konzepte auseinanderzuhalten:
- Berechtigung (Permission): atomare Befugnisse, die von Discord definiert sind, etwa
BanMembers,ManageGuildoderKickMembers. Die effektiven Berechtigungen eines Mitglieds sind die Vereinigung der Berechtigungen aller seiner Rollen. - Rolle (Role): serverspezifische Gruppen mit Namen und Farbe. Rollen wie „Moderator" oder „VIP" sind deine eigene Erfindung; Discord kennt sie nicht, es sieht nur die Berechtigungen, die sie tragen.
Ein gutes Berechtigungssystem nutzt beides: Den groben Filter liefern Discords Berechtigungsflags, die feine Steuerung kommt aus deiner eigenen Rollenlogik.
Erste Verteidigungslinie: setDefaultMemberPermissions
Wenn du einen Slash-Befehl definierst, kannst du Discord direkt mitteilen, welche Berechtigung er erfordert. Dadurch sehen Nutzer ohne diese Berechtigung den Befehl nicht einmal im Menü — der sauberste Schutz, denn die Prüfung erfolgt auf Discords Seite.
// commands/moderation/ban.js
const { SlashCommandBuilder, PermissionFlagsBits } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('ban')
.setDescription('Bannt ein Mitglied vom Server')
.addUserOption((o) =>
o.setName('mitglied').setDescription('Zu bannendes Mitglied').setRequired(true))
.setDefaultMemberPermissions(PermissionFlagsBits.BanMembers),
async execute(interaction) {
// ...
},
};
Hier zeigt setDefaultMemberPermissions den Befehl nur Rollen, die BanMembers besitzen. Das ist ein Standard-Ausgangspunkt; Serveradministratoren können ihn pro Rolle oder Kanal über Discords „Integrationen"-Einstellungen überschreiben. Verlasse dich trotzdem nicht allein darauf — du musst auch in deinem Code prüfen.
Die Berechtigung im Code prüfen
Zusätzlich zu Discords UI-Filter ist das erneute Prüfen der Berechtigung des Aufrufers serverseitig während der Ausführung die Grundlage der Sicherheit. interaction.memberPermissions gibt ein PermissionsBitField zurück, das du mit .has() abfragst.
async execute(interaction) {
if (!interaction.memberPermissions.has(PermissionFlagsBits.BanMembers)) {
return interaction.reply({
content: 'Du brauchst die Berechtigung **Mitglieder bannen** für diesen Befehl.',
ephemeral: true,
});
}
// Berechtigung erteilt, weiter mit der Verarbeitung
}
Dank ephemeral: true sieht nur die Person, die den Befehl ausgeführt hat, die Warnung; der Kanal füllt sich nicht mit Nachrichten unbefugter Versuche.
Abläufe, die eine Rolle erfordern
Manchmal hängt ein Befehl nicht von einer eingebauten Discord-Berechtigung ab, sondern von einer Rolle, die du definiert hast — zum Beispiel sollen nur Personen mit der Rolle „Support-Team" ein Ticket schließen dürfen. Du prüfst die Rollen eines Mitglieds über interaction.member.roles.cache. Eine Rolle per ID abzufragen ist weit zuverlässiger als per Name, weil Rollen umbenannt werden können.
const SUPPORT_ROLLEN_ID = '123456789012345678';
async execute(interaction) {
const erlaubt = interaction.member.roles.cache.has(SUPPORT_ROLLEN_ID);
if (!erlaubt) {
return interaction.reply({
content: 'Nur das Support-Team kann diese Aktion ausführen.',
ephemeral: true,
});
}
// Ablauf zum Schließen des Tickets...
}
Möchtest du eine von mehreren Rollen akzeptieren, lege die erlaubten IDs in ein Array und prüfe mit some:
const ERLAUBTE_ROLLEN = ['111...', '222...'];
const erlaubt = ERLAUBTE_ROLLEN.some((id) => interaction.member.roles.cache.has(id));
Wiederholung vermeiden: eine wiederverwendbare Berechtigungsschicht
Dieselben if-Blöcke in jeden Befehl zu kopieren ist fehleranfällig. Ein saubererer Ansatz ist, der Befehlsdatei einen Berechtigungsvertrag hinzuzufügen und die Prüfung im zentralen interactionCreate-Event durchzuführen. Der Befehl deklariert nur seine Anforderung; der Handler setzt sie durch.
// commands/moderation/clear.js
module.exports = {
data: /* ...SlashCommandBuilder... */,
permissions: [PermissionFlagsBits.ManageMessages], // erforderliche Berechtigungen
roles: ['MOD_ROLLEN_ID'], // erforderliche Rollen (optional)
async execute(interaction) { /* ... */ },
};
// in events/interactionCreate.js
const command = interaction.client.commands.get(interaction.commandName);
if (!command) return;
// Berechtigungsprüfung
if (command.permissions?.length) {
const fehlend = command.permissions.filter(
(p) => !interaction.memberPermissions.has(p));
if (fehlend.length) {
return interaction.reply({
content: 'Dir fehlen die für diesen Befehl erforderlichen Berechtigungen.',
ephemeral: true,
});
}
}
// Rollenprüfung
if (command.roles?.length) {
const ok = command.roles.some(
(id) => interaction.member.roles.cache.has(id));
if (!ok) {
return interaction.reply({
content: 'Du darfst diesen Befehl nicht verwenden.',
ephemeral: true,
});
}
}
await command.execute(interaction);
Um nun einen neuen geschützten Befehl hinzuzufügen, musst du nur ein permissions- oder roles-Feld in die Datei schreiben; der wiederholte Prüfcode lebt an einer einzigen Stelle.
Vergiss die eigenen Berechtigungen des Bots nicht
Ein häufiger Fehler: Selbst wenn der Nutzer berechtigt ist, fehlt dem Bot selbst möglicherweise die Berechtigung, die Aktion auszuführen. Prüfe vor dem Bannen die Rollenhierarchie und die Berechtigungen des Bots, sonst gibt die API einen Fehler zurück.
const ziel = interaction.options.getMember('mitglied');
const me = interaction.guild.members.me;
if (!me.permissions.has(PermissionFlagsBits.BanMembers)) {
return interaction.reply({
content: 'Mir fehlt das Bann-Recht. Bitte prüfe die Rollenberechtigungen des Bots.',
ephemeral: true,
});
}
if (ziel && ziel.roles.highest.position >= me.roles.highest.position) {
return interaction.reply({
content: 'Dieses Mitglied hat eine höhere Rolle als ich, ich kann nicht handeln.',
ephemeral: true,
});
}
In Discord kann ein Mitglied nur gegen Mitglieder vorgehen, deren höchste Rolle unter seiner eigenen liegt. Dieselbe Regel gilt für den Bot; denke also daran, die Rolle des Bots in der Rollenliste hoch genug zu platzieren.
Häufig gestellte Fragen
Reicht setDefaultMemberPermissions nicht — warum auch im Code prüfen?
Weil setDefaultMemberPermissions nur die UI-Sichtbarkeit beeinflusst und von Serveradministratoren überschrieben werden kann. Die eigentliche Sicherheitsentscheidung muss im Code, serverseitig, getroffen werden. Beide Schichten zusammen bieten sowohl eine saubere Nutzererfahrung als auch zuverlässigen Schutz.
Soll ich eine Rolle per Name oder per ID prüfen?
Immer per ID. Rollennamen können sich ändern, und mehrere Rollen können denselben Namen tragen; die ID ist eindeutig und dauerhaft. Du kopierst die ID per Rechtsklick auf die Rolle, wenn der Entwicklermodus in Discord aktiviert ist.
Kann ich die Berechtigungskonfiguration vom Code trennen?
Ja. Mit zunehmender Skalierung ist es eine gute Idee, Rollen-IDs und Befehlsberechtigungen in einer Datenbank oder einer config-Datei zu speichern. So kann jeder Server seine eigenen Rollen definieren, und du musst keinen Code deployen, nur um zu ändern, wer Zugriff hat.
Leckt das Berechtigungssystem deines Bots, oder willst du es von Grund auf neu bauen? Wir können Berechtigungs- und Rollenprüfungen, die Berechtigungshierarchie des Bots und eine zentrale Autorisierungsschicht gemeinsam auf ein solides Fundament stellen. Kontaktiere mich und lass uns deinen Bot absichern.