Die Allgemeine Datenschutzverordnung (GDPR) ist eine europäische Verordnung zum Datenschutz und zur Privatsphäre.Es gewährt Personen das Recht, die Löschung ihrer personenbezogenen Daten zu beantragen, bekannt als das Recht auf Löschung.Wenn du irgendeine persönlich identifizierbare Information (personenbezogene Daten ) deiner Benutzer speicherst, wie ihre Benutzer-IDs, musst du die Anforderungen der DSGVO einhalten, indem du diese Informationen löschst, wenn du eine Anfrage eines Benutzers erhältst.
Anstatt Anfragen manuell zu bearbeiten, kannst du einen Webhook einrichten und einen Bot innerhalb einer Dritt-Messaging-Anwendung verwenden, um den Prozess zu automatisieren.Da Datenspeicher die häufigste Art sind, um PII-Daten zu speichern, bietet dieses Tutorial ein Beispiel, wie man einen Bot innerhalb von Guilded oder Discord erstellt, der die Open Cloud API für Datenspeicher verwendet, um PII-Daten als Automatisierungslösung zu löschen.
Arbeitsfluss
Nach Abschluss dieses Tutorials solltest du in der Lage sein, ein lokal ausgeführtes benutzerdefiniertes Programm zu erstellen, das die Bearbeitung von Löschanfragen von Benutzern automatisiert.Der Workflow für diesen Prozess ist wie folgt:
- Roblox-Unterstützung erhält eine Löschanfrage von einem Benutzer.
- Der Roblox-Webhook wird ausgelöst, der die Benutzer-ID und eine Liste von Startplatz-IDs für die Erlebnisse enthält, denen sie sich im Payload angeschlossen haben.
- Ihr Bot hört auf diese Webhook-Benachrichtigungen, überprüft ihre Authentizität und nutzt die Open Cloud API für Datenspeicher, um die PII-Daten, die in Datenspeichern gespeichert sind, zu löschen.
- Der Bot reagiert auf die Webhook-Nachricht in Discord oder Guilded mit dem Status.

Konfiguriere einen Webhook mit Integration durch Dritte
Bevor du einen Bot erstellst, richte einen Server mit Webhook-Integration auf der Drittanbieter-Messaging-Anwendung ein.Verwende dann den Server, um einen Webhook auf dem Creator-Dashboard zu konfigurieren.
Einen Server einrichten
Die folgenden Schritte zeigen, wie man den Server mit Guilded oder Discord einrichtet.
- Erstelle einen neuen Guilded-Server. Wenn du mit dem Prozess nicht vertraut bist, siehe Guilded-Unterstützung.
- Unter den Datenschutz -Einstellungen stelle den Server auf privater Serverein.Der Server erstellt automatisch einen privaten #general -Kanal als Standardkanal.
- Erstelle eine Webhook-Integration mit dem neuen Server und gib ihm einen Namen, den du leicht verstehen kannst, wie z. B. GDPR Hook.Wenn du mit dem Prozess nicht vertraut bist, siehe Guilded-Unterstützung.
- Kopiere die Webhook-URL und speichere sie an einem sicheren Ort.Erlaube nur vertrauenswürdigen Teammitgliedern darauf zuzugreifen, da das Lecken der URL es schlechten Akteuren ermöglichen kann, gefälschte Nachrichten zu senden und deine Benutzerdaten möglicherweise zu löschen.
Konfiguriere einen Webhook auf Roblox
Nachdem du die URL des Drittservers erhalten hast, verwende sie, um einen Webhook zu konfigurieren auf dem Creator-Dashboard.stellen Sie sicher, dass Sie die folgenden Einstellungen durchführen:
- Füge die Guilded- oder Discord-Server-URL als die Webhook-URL hinzu.
- Füge ein benutzerdefiniertes Geheimnis hinzu.Obwohl ein Geheimnis optional ist, um die Konfiguration abzuschließen, solltest du eines einfügen, um schlechten Akteuren zu verhindern, dass sie sich als Roblox ausgeben und deine Daten löschen.Für weitere Informationen über die Verwendung eines Geheimnisses siehe Überprüfen der Webhook-Sicherheit.
- Wählen Sie Recht auf Löschungsanfrage unter Auslöser .
Du kannst den Webhook mit der Testantwort -Taste testen, um zu sehen, ob du eine Benachrichtigung in deinem Serverkanal #general von Roblox erhältst.Wenn du die Benachrichtigungennicht erhältst, versuche es erneut oder überprüfe deine Servereinstellungen, um den Fehler zu beheben.

Konfiguriere einen Bot
Nachdem du den Webhook hinzugefügt hast, verwende ihn, um den Bot mit den folgenden Schritten zu konfigurieren:
Öffne die Alle Server -Liste, indem du auf ihr Symbol klickst oder verwende den Tastenkombination:
- CtrlS auf Windows.
- ⌘S auf dem Mac.
Wählen Sie Ihren Server für das Empfangen von Löschbenachrichtigungen aus.
Erweitere die Liste unter Server-Home und wähle Bots verwalten .
Der Server erstellt automatisch einen privaten #general -Kanal als Standardkanal.
Klicke auf die Schaltfläche Erstelle einen Bot und gib einen Bot-Namen ein. Guilded leitet dich auf die Bot-Konfigurationsseite um.
Wählen Sie den API -Abschnitt auf der Bot-Konfigurationsseite aus.
Klicken Sie unter der Token -Sektion auf die Schaltfläche Token generieren .
Speichern und lagern Sie das generierte Token an einem sicheren Ort.
Erstellen eines Open-Cloud-API-Schlüssels
Um deinem Drittanbieter-Bot Zugriff auf deine Datenlagern zu gewähren, um PII-Daten von Benutzern zu speichern, erstelle einen Open Cloud API-Schlüssel, der auf deine Erlebnisse zugreifen kann, und füge die Löschen-Eintrag Berechtigung von Datenlagern für Datenlöschung hinzu.Wenn du strukturierte Datenstores für die Speicherung von personenbezogene Daten verwendest, musst du auch die Schreib -Berechtigung von strukturierten Datenstores hinzufügen.Nach Abschluss kopieren und speichern Sie den API-Schlüssel an einem sicheren Ort, um ihn in späteren Schritten zu verwenden.
Erhalte Identifikatoren von Erlebnissen und Orten
Um den Bot zu orten, die PII-Daten, die von Benutzern für die Löschung angefordert wurden, zu finden, erhalten Sie die folgenden Identifikatoren aller Erlebnisse, für die Sie den Bot verwenden möchten:
- Die Universum-ID , der eindeutige Identifikator deiner Erlebnis.
- Die Startplatz-ID , der eindeutige Identifikator des Startplatzes eines Erlebnisses.
Um diese Identifikatoren zu erhalten:
Navigiere zum Creator-Dashboard.
Bewegen Sie den Mauszeiger über eine Miniaturansichteines Erlebnisses, klicken Sie auf die Schaltfläche ⋯ und wählen Sie Universitäts-ID kopieren und Startplatz-ID kopieren , jeweils respektive aus.
Skripte hinzufügen
Nachdem du den Webhook, den Bot und den API-Schlüssel für Datenspeicher eingerichtet hast, füge sie den Skripten hinzu, die die Automatisierungslogik des Bots implementieren.Das folgende Beispiel verwendet Python 3:
Installieren Sie Python-Bibliotheken mit den folgenden Befehlen:
Bibliotheken installierenpip3 install guilded.py==1.8.0pip3 install requestspip3 install urllib3==1.26.6Kopiere und speichere die folgenden Skripte, die entsprechend verschiedener Teile der Bot-Logik in demselben Verzeichnis sind:
bot_config.pyBOT_TOKEN = ""OPEN_CLOUD_API_KEY = ""ROBLOX_WEBHOOK_SECRET = ""# Wörterbuch der Startplatz-ID zu# (Universal-ID, Liste von (Datenspeichername, Umfang und Schlüssel)) für# Standard-Datenspeicher# Benutzerdaten, die unter diesen Einträgen gespeichert wurden, werden gelöschtSTANDARD_DATA_STORE_ENTRIES = {# Startplatz-ID111111111: (# Universitäts-ID222222222,[("StandardDataStore1", "Scope1", "Key1_{user_id}"),("StandardDataStore1", "Scope1", "Key2_{user_id}"),("StandardDataStore2", "Scope1", "Key3_{user_id}")]),33333333: (444444444,[("StandardDataStore3", "Scope1", "Key1_{user_id}")])}# Wörterbuch der Startplatz-ID zu# (Universal-ID, Liste von (Datenspeichername, Umfang und Schlüssel)) für# Bestellte Datenspeicher# Benutzerdaten, die unter diesen Einträgen gespeichert wurden, werden gelöschtORDERED_DATA_STORE_ENTRIES = {111111111: (222222222,[("OrderedDataStore1", "Scope2", "Key4_{user_id}")])}data_stores_api.pyimport requestsimport bot_configfrom collections import defaultdict"""Calls Data Stores Open Cloud API to delete all entries for a user_id configured inSTANDARD_DATA_STORE_ENTRIES. Returns a list of successful deletions and failures to delete."""def delete_standard_data_stores(user_id, start_place_ids):successes = defaultdict(list)failures = defaultdict(list)for owned_start_place_id in bot_config.STANDARD_DATA_STORE_ENTRIES:if owned_start_place_id not in start_place_ids:continueuniverse_id, universe_entries = bot_config.STANDARD_DATA_STORE_ENTRIES[owned_start_place_id]for (data_store_name, scope, entry_key) in universe_entries:entry_key = entry_key.replace("{user_id}", user_id)response = requests.delete(f"https://apis.roblox.com/datastores/v1/universes/{universe_id}/standard-datastores/datastore/entries/entry",headers={"x-api-key": bot_config.OPEN_CLOUD_API_KEY},params={"datastoreName": data_store_name,"scope": scope,"entryKey": entry_key})if response.status_code in [200, 204]:successes[owned_start_place_id].append((data_store_name, scope, entry_key))else:failures[owned_start_place_id].append((data_store_name, scope, entry_key))return successes, failures"""Calls Ordered Data Stores Open Cloud API to delete all entries for a user_id configured inORDERED_DATA_STORE_ENTRIES. Returns a list of successful deletions and failures to delete."""def delete_ordered_data_stores(user_id, start_place_ids):successes = defaultdict(list)failures = defaultdict(list)for owned_start_place_id in bot_config.ORDERED_DATA_STORE_ENTRIES:if owned_start_place_id not in start_place_ids:continueuniverse_id, universe_entries = bot_config.ORDERED_DATA_STORE_ENTRIES[owned_start_place_id]for (data_store_name, scope, entry_key) in universe_entries:entry_key = entry_key.replace("{user_id}", user_id)response = requests.delete(f"https://apis.roblox.com/ordered-data-stores/v1/universes/{universe_id}/orderedDatastores/{data_store_name}/scopes/{scope}/entries/{entry_key}",headers={"x-api-key": bot_config.OPEN_CLOUD_API_KEY})if response.status_code in [200, 204, 404]:successes[owned_start_place_id].append((data_store_name, scope, entry_key))else:failures[owned_start_place_id].append((data_store_name, scope, entry_key))return successes, failuresmessage_parser.pyimport timeimport hmacimport hashlibimport reimport base64import bot_config"""Parses received message for Roblox signature and timestamp, the footer is only set if youconfigured webhook secret"""def parse_footer(message):if not message.embeds[0].footer or \not message.embeds[0].footer.text:return "", 0footer_match = re.match(r"Roblox-Signature: (.*), Timestamp: (.*)",message.embeds[0].footer.text)if not footer_match:return "", 0else:signature = footer_match.group(1)timestamp = int(footer_match.group(2))return signature, timestamp"""Verifies Roblox signature with configured secret to check for validity"""def validate_signature(message, signature, timestamp):if not message or not signature or not timestamp:return False# Verhindert Wiedergabeangriff innerhalb von 300 Sekunden-Fensterrequest_timestamp_ms = timestamp * 1000window_time_ms = 300 * 1000oldest_timestamp_allowed = round(time.time() * 1000) - window_time_msif request_timestamp_ms < oldest_timestamp_allowed:return False# Signatur validierttimestamp_message = "{}.{}".format(timestamp, message.embeds[0].description)digest = hmac.new(bot_config.ROBLOX_WEBHOOK_SECRET.encode(),msg=timestamp_message.encode(),digestmod=hashlib.sha256).digest()validated_signature = base64.b64encode(digest).decode()if signature != validated_signature:return False# Gültige Signaturreturn True"""Parses a received webhook messaged on Discord or Guilded. Extracts user ID, prevents replay attackbased on timestamp received, and verifies Roblox signature with configured secret to check forvalidity."""def parse_message(message):# Parsiert empfangene Nachricht für Benutzer-ID und Spiel-IDif len(message.embeds) != 1 or \not message.embeds[0].description:return "", []description_match = re.match(r"You have received a new notification for Right to Erasure for the User Id: (.*) in " +r"the game\(s\) with Ids: (.*)",message.embeds[0].description)if not description_match:return "", []user_id = description_match.group(1)start_place_ids = set(int(item.strip()) for item in description_match.group(2).split(","))signature, timestamp = parse_footer(message)if validate_signature(message, signature, timestamp):return user_id, start_place_idselse:return "", []guilded_bot.pyimport guildedimport jsonimport bot_configimport data_stores_apiimport message_parserdef run():client = guilded.Client()@client.eventasync def on_ready():print(f"{client.user} is listening to Right to Erasure messages")"""Handler for webhook messages from Roblox"""@client.eventasync def on_message(message):# Parsiert und validiert Nachrichtuser_id, start_place_ids = message_parser.parse_message(message)if not user_id or not start_place_ids:return# Löscht Standard-Datenspeicher-Benutzerdaten[successes, failures] = data_stores_api.delete_standard_data_stores(user_id, start_place_ids)if successes:await message.reply(f"Deleted standard data stores data for " +f"user ID: {user_id}, data: {dict(successes)}")if failures:await message.reply(f"Failed to delete standard data stores data for " +f"user ID: {user_id}, data: {dict(failures)}")# Löscht die Daten von bestellten Datenlagern des Benutzers[successes, failures] = data_stores_api.delete_ordered_data_stores(user_id, start_place_ids)if successes:await message.reply(f"Deleted ordered data stores data for " +f"user ID: {user_id}, data: {dict(successes)}")if failures:await message.reply(f"Failed to delete ordered data stores data for " +f"user ID: {user_id}, data: {dict(failures)}")client.run(bot_config.BOT_TOKEN)if __name__ == "__main__":run()Auf der bot_config.py Datei für die Hauptkonfiguration des Bots:
- Setze BOT_TOKEN auf das Token, das von deinem Bot erzeugt wurde.
- Setze OPEN_CLOUD_API_KEY als API-Schlüssel, den du erstellt hast, ein.
- Setze ROBLOX_WEBHOOK_SECRET als Geheimnis fest, das du festlegst, wenn du den Webhook im Creator-Dashboard konfigurierst.
- In STANDARD_DATA_STORE_ENTRIES und ORDERED_DATA_STORE_ENTRIES Wörterbüchern für die Lokalisierung des Datenlagers jedes Eintrags zum löschen:
- Füge deine kopierten Startplatz-IDs als Schlüssel hinzu.
- Füge Universe-IDs als erstes Element des tuple-Werts hinzu.
- Ersetze das zweite Element der Tuplizität durch den Namen, den Umfang, den Namen des Eingabeschlüssels und die zugeordnete Benutzer-ID deiner Datenstores.Wenn du ein anderes Datenmodell verwendest, passe es entsprechend deinem eigenen Datenmodell an.
Führen Sie den folgenden Befehl aus, um den Bot zu starten:
Guilded-Bot ausführenpython3 guilded_bot.pyDer Bot beginnt dann, Roblox-Webhooks zu hören und zu überprüfen, und ruft den Open Cloud-Endpunkt auf, den entsprechenden Storezu löschen.
Testen
Du kannst eine Testnachricht erstellen und ausführen, um zu überprüfen, dass dein benutzerdefiniertes Programm richtig mit Löschanfragen und der Löschung von PII-Daten umgehen kann:
Sende eine HTTP-POST-Anfrage an deinen Guilded oder Discord-Webhook-Server mit dem folgenden Körper:
Beispielanfragecurl -X POST {serverUrl}-H 'Content-Type: application/json'-d '{"embeds":[{"title":"RightToErasureRequest","description":"You have received a new notification for Right to Erasure for the User Id: {userIds} in the game(s) with Ids: {gameIds}","footer":{"icon_url":"https://create.roblox.com/dashboard/assets/webhooks/roblox_logo_metal.png","text":"Roblox-Signature: {robloxSignature}, Timestamp: {timestamp}"}}]}'Wenn du ein Webhook-Geheimnis hast:
- Erstelle ein Roblox-Signature durch die Anwendung der HMAC-SHA256-Verschlüsselung auf deinen Schlüssel.
- Stellen Sie die aktuelle Zeit mit UTC-Zeit戳 in Sekunden als Timestamp ein.
Füge das description im folgenden Format zusammen:
Description Field Format{Timestamp}. You have received a new notification for Right to Erasure for the User Id: {userId} in the game(s) with Ids: {gameIds}`.Zum Beispiel:
Example Description Field1683927229. You have received a new notification for Right to Erasure for the User Id: 2425654247 in the game(s) with Ids: 10539205763, 13260950955
Dein Programm sollte in der Lage sein, zu identifizieren, dass deine Nachricht von der offiziellen Roblox-Quelle stammt, da du die Nachricht mit deinem Geheimnis verschlüsselt hast.Es sollte dann die PII-Daten löschen, die mit Ihrer Anfrage verbunden sind.
Beispielkörper
{
"embeds": [
{
"title": "RightToErasureRequest",
"description": "You have received a new notification for Right to Erasure for the User Id: 2425654247 in the game(s) with Ids: 10539205763, 13260950955",
"footer": {
"icon_url": "https://erstellen.roblox.com/ashboard/assets/webhooks/roblox_logo_metal.png",
"text": "Roblox-Signature: UIe6GJ78MHCmU/zUKBYP3LV0lAqwWRFR6UEfPt1xBFw=, Timestamp: 1683927229"
}
}
]
}