อัตโนมัติคำขอสิทธิ์การลบ

*เนื้อหานี้แปลโดยใช้ AI (เวอร์ชัน Beta) และอาจมีข้อผิดพลาด หากต้องการดูหน้านี้เป็นภาษาอังกฤษ ให้คลิกที่นี่

กฎการคุ้มครองข้อมูลทั่วไป (GDPR) เป็นกฎระเบียบของยุโรปเกี่ยวกับการคุ้มครองข้อมูลและความเป็นส่วนตัว มันมอบสิทธิให้บุคคลในการขอให้ลบข้อมูลส่วนบุคคลของตน ซึ่งเรียกว่าคำว่า สิทธิ์การลบ หากคุณเก็บข้อมูล ข้อมูลที่สามารถระบุตัวตนได้ (PII) ของผู้ใช้ เช่น รหัสผู้ใช้ของพวกเขา คุณต้องปฏิบัติตามข้อกำหนดของ GDPR โดยการลบข้อมูลนี้เมื่อได้รับคำขอจากผู้ใช้

แทนที่จะจัดการคำขอด้วยตนเอง คุณสามารถ ตั้งเว็บฮุค และใช้บอทภายในแอปพลิเคชันการสื่อสารของบุคคลที่สามเพื่อทำให้กระบวนการเป็นอัตโนมัติ โดย ที่เก็บข้อมูล เป็นวิธีที่พบบ่อยที่สุดในการเก็บข้อมูล PII บทแนะนำนี้ให้ตัวอย่างว่าคุณจะสร้างบอทภายใน Discord ที่ใช้ Open Cloud API สำหรับที่เก็บข้อมูล เพื่อลบข้อมูล PII เป็นโซลูชันอัตโนมัติได้อย่างไร

การทำงาน

เมื่อคุณทำตามบทแนะนำนี้เรียบร้อยแล้ว คุณควรจะสามารถสร้างโปรแกรมที่ทำงานในเครื่องที่กำหนดเองซึ่งอัตโนมัติการจัดการคำขอสิทธิ์การลบจากผู้ใช้ ขั้นตอนการทำงานสำหรับกระบวนการนี้มีดังนี้:

  1. การสนับสนุนของ Roblox รับคำขอสิทธิ์การลบจากผู้ใช้
  2. เว็บฮุคของ Roblox ถูกกระตุ้น โดยมีรหัสผู้ใช้และรายการรหัสที่เริ่มเกมที่ผู้ใช้เข้าร่วมใน Payload
  3. บอทของคุณฟังการแจ้งเตือนเว็บฮุคเหล่านี้ ยืนยันความถูกต้องของพวกเขา และใช้ Open Cloud API สำหรับที่เก็บข้อมูล เพื่อลบข้อมูล PII ที่จัดเก็บอยู่ในที่เก็บข้อมูล
  4. บอทตอบกลับข้อความเว็บฮุคใน Discord ด้วยสถานะการลบ

ตั้งค่าเว็บฮุคกับการผสานงานของบุคคลที่สาม

ก่อนที่คุณจะสร้างบอท ให้ตั้งค่าเซิร์ฟเวอร์ด้วยการรวม webhook บนแอปพลิเคชันการสื่อสารของบุคคลที่สาม จากนั้นใช้เซิร์ฟเวอร์เพื่อกำหนดค่าเว็บฮุคบน Creator Dashboard

ตั้งค่าเซิร์ฟเวอร์

ขั้นตอนต่อไปนี้แสดงวิธีตั้งค่าเซิร์ฟเวอร์โดยใช้ Discord

  1. สร้างเซิร์ฟเวอร์ Discord ใหม่ หากคุณไม่คุ้นเคยกับกระบวนการนี้ โปรดดูที่ Discord Support.

  2. เซิร์ฟเวอร์จะสร้างช่อง #general โดยอัตโนมัติเป็นช่องเริ่มต้นของคุณ คลิกที่ไอคอน แก้ไขช่อง ของช่อง #general

  3. ภายใต้ สิทธิ์ ให้ตั้งช่องให้เป็นส่วนตัว

  4. สร้างการรวมเว็บฮุคกับเซิร์ฟเวอร์ใหม่ ตั้งชื่อให้เป็น GDPR Hook หากคุณไม่คุ้นเคยกับกระบวนการนี้ โปรดดูที่ Discord Support.

  5. คัดลอก URL ของเว็บฮุคและเก็บไว้ในที่ปลอดภัย อนุญาตให้เฉพาะสมาชิกทีมที่เชื่อถือได้เข้าถึงเท่านั้น เพราะการเปิดเผย URL อาจอนุญาตให้ผู้ที่ไม่ดีส่งข้อความปลอมและอาจลบข้อมูลของผู้ใช้ของคุณ

กำหนดค่าเว็บฮุคบน Roblox

หลังจากที่คุณได้รับ URL เซิร์ฟเวอร์ของบุคคลที่สาม ใช้มันเพื่อ กำหนดค่าเว็บฮุค บน Creator Dashboard โดยให้แน่ใจว่าคุณทำการตั้งค่าดังต่อไปนี้:

  • เพิ่ม URL เซิร์ฟเวอร์ Discord เป็น Webhook URL
  • รวม Secret ที่กำหนดเอง แม้ว่า secret จะเป็นตัวเลือกในการทำให้การกำหนดค่าการตั้งค่าเสร็จสมบูรณ์ แต่คุณควรรวมหนึ่งเพื่อป้องกันไม่ให้ผู้ไม่ดีเลียนแบบ Roblox และลบข้อมูลของคุณ สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการใช้ secret โปรดดูที่ ตรวจสอบความปลอดภัยของเว็บฮุค.
  • เลือก Right to Erasure Request ภายใต้ Triggers.

คุณสามารถทดสอบเว็บฮุคโดยใช้ปุ่ม Test Response เพื่อดูว่าคุณได้รับการแจ้งเตือนในช่อง #general ของเซิร์ฟเวอร์จาก Roblox หากคุณไม่ได้รับการแจ้งเตือน ลองอีกครั้งหรือเช็คการตั้งค่าเซิร์ฟเวอร์ของคุณเพื่อหาข้อผิดพลาด

กำหนดค่าบอท

หลังจากที่คุณเพิ่มเว็บฮุค ใช้มันเพื่อกำหนดค่าบอทด้วยขั้นตอนต่อไปนี้ สำหรับข้อมูลเพิ่มเติม โปรดดูที่ เอกสาร Discord.

  1. ไปที่ หน้า Applications.
  2. สร้างแอปพลิเคชันใหม่และตั้งชื่อเป็น GDPR Bot.
  3. ระบบจะเปลี่ยนเส้นทางไปยังการตั้งค่า ข้อมูลทั่วไป ของบอท คัดลอกและบันทึก Application ID ในที่ปลอดภัย
  4. ภายใต้เมนูการตั้งค่า เลือก OAuth2
  5. ไปที่การตั้งค่า OAuth2
    1. เปิดใช้งานสโคป บอท จะมีรายการสิทธิ์ของบอทเพิ่มเติมแสดงขึ้น
    2. เพิ่มสิทธิ์ ผู้ดูแลระบบ บันทึกการเปลี่ยนแปลงของคุณ
    3. บันทึก URL ที่สร้างขึ้น
  6. คัดลอก URL ที่สร้างขึ้น ทิ้งหน้าการตั้งค่าแอปพลิเคชันไว้ในสถานะเปิด
  7. ไปที่ URL ที่สร้างขึ้น เลือกเซิร์ฟเวอร์เป้าหมาย คลิกที่ปุ่ม ดำเนินการต่อ แล้วคลิกปุ่ม อนุญาต
  8. กลับไปที่หน้าการตั้งค่าของแอปพลิเคชันและไปที่การตั้งค่าของบอท
  9. ภายใต้ส่วน Privileged Gateway Intents เปิดใช้งาน Message Content Intent
  10. ในการตั้งค่าบอท > ส่วน Build-A-Bot บันทึกโทเค็นบอทในที่ปลอดภัยสำหรับขั้นตอนในภายหลัง ถ้าคุณไม่เห็นโทเค็นให้คลิกที่ปุ่ม Reset Token เพื่อสร้างโทเค็นใหม่

สร้างคีย์ Open Cloud API

เพื่อให้บอทของคุณเข้าถึงที่เก็บข้อมูลของคุณสำหรับการเก็บข้อมูล PII ของผู้ใช้ สร้างคีย์ Open Cloud API ที่สามารถเข้าถึงเกมของคุณและเพิ่มสิทธิ์ Delete Entry ของที่เก็บข้อมูลสำหรับการลบข้อมูล หากคุณใช้ที่เก็บข้อมูลที่เรียงลำดับสำหรับการเก็บข้อมูล PII คุณยังต้องเพิ่มสิทธิ์ Write ของที่เก็บข้อมูลที่เรียงลำดับ หลังจากเสร็จสิ้น ให้นำคีย์ API ไปเก็บในสถานที่ปลอดภัยเพื่อนำไปใช้ในขั้นตอนถัดไป

รับตัวระบุของเกมและที่ตั้ง

เพื่อให้บอทสามารถค้นหาข้อมูล PII ที่ร้องขอโดยผู้ใช้ในการลบ ให้รับตัวระบุของทุกเกมที่คุณตั้งใจจะใช้บอทดังต่อไปนี้:

  • Universe ID ซึ่งเป็นตัวระบุเฉพาะของเกมของคุณ
  • Start Place ID ซึ่งเป็นตัวระบุเฉพาะของที่ตั้งเริ่มต้นของเกม

เพื่อรับตัวระบุเหล่านี้:

  1. ไปที่ Creator Dashboard

  2. เลื่อนเมาส์ไปที่ภาพขนาดย่อของเกม คลิกที่ปุ่ม แล้วเลือก คัดลอกรหัส Universe และ คัดลอกรหัส Start Place ตามลำดับ

เพิ่มสคริปต์

หลังจากที่คุณตั้งค่าเว็บฮุค บอท และคีย์ API สำหรับที่เก็บข้อมูลเสร็จแล้ว ให้เพิ่มให้กับสคริปต์ที่ implement logic อัตโนมัติของบอท ตัวอย่างด้านล่างนี้ใช้ Python 3

  1. ติดตั้งไลบรารี Python โดยใช้คำสั่งต่อไปนี้:

    ติดตั้ง Libraries

    pip3 install discord
    pip3 install requests
    pip3 install urllib3==1.26.6
  2. คัดลอกและบันทึกสคริปต์ต่อไปนี้ที่สอดคล้องกับส่วนต่าง ๆ ของ logic บอทในไดเรกทอรีเดียวกัน:

    bot_config.py

    BOT_TOKEN = ""
    OPEN_CLOUD_API_KEY = ""
    ROBLOX_WEBHOOK_SECRET = ""
    # พจนานุกรมของ Start Place ID ไปยัง
    # (Universe ID, รายการของ (ชื่อที่เก็บข้อมูล, สโคป, และคีย์เอนทรี)) สำหรับ
    # Standard Data Stores
    # ข้อมูลผู้ใช้ที่จัดเก็บภายใต้เอนทรีเหล่านี้จะถูกลบ
    STANDARD_DATA_STORE_ENTRIES = {
    # Start Place ID
    111111111: (
    # Universe ID
    222222222,
    [
    ("StandardDataStore1", "Scope1", "Key1_{user_id}"),
    ("StandardDataStore1", "Scope1", "Key2_{user_id}"),
    ("StandardDataStore2", "Scope1", "Key3_{user_id}")
    ]
    ),
    33333333: (
    444444444,
    [
    ("StandardDataStore3", "Scope1", "Key1_{user_id}")
    ]
    )
    }
    # พจนานุกรมของ Start Place ID ไปยัง
    # (Universe ID, รายการของ (ชื่อที่เก็บข้อมูล, สโคป, และคีย์เอนทรี)) สำหรับ
    # Ordered Data Stores
    # ข้อมูลผู้ใช้ที่จัดเก็บภายใต้เอนทรีเหล่านี้จะถูกลบ
    ORDERED_DATA_STORE_ENTRIES = {
    111111111: (
    222222222,
    [
    ("OrderedDataStore1", "Scope2", "Key4_{user_id}")
    ]
    )
    }
    data_stores_api.py

    import requests
    import bot_config
    from collections import defaultdict
    """
    เรียกใช้ Data Stores Open Cloud API เพื่อลบเอนทรีทั้งหมดสำหรับ user_id ที่กำหนดใน
    STANDARD_DATA_STORE_ENTRIES คืนค่ารายการของการลบที่สำเร็จและความล้มเหลวในการลบ
    """
    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.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
    """
    เรียกใช้ Ordered Data Stores Open Cloud API เพื่อลบเอนทรีทั้งหมดสำหรับ user_id ที่กำหนดใน
    ORDERED_DATA_STORE_ENTRIES คืนค่ารายการของการลบที่สำเร็จและความล้มเหลวในการลบ
    """
    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.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, failures
    message_parser.py

    import time
    import hmac
    import hashlib
    import re
    import base64
    import bot_config
    """
    วิเคราะห์ข้อความที่ได้รับสำหรับลายเซ็นและเวลา ในฟุตเตอร์จะตั้งค่าเฉพาะถ้าคุณ
    กำหนดเว็บฮุค secret
    """
    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
    """
    ยืนยันลายเซ็น Roblox ด้วย secret ที่กำหนดเพื่อตรวจสอบความถูกต้อง
    """
    def validate_signature(message, signature, timestamp):
    if not message or not signature or not timestamp:
    return False
    # ป้องกันการโจมตีแบบ replay ภายใน 300 วินาที
    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
    # ยืนยันลายเซ็น
    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
    # ลายเซ็นถูกต้อง
    return True
    """
    วิเคราะห์ข้อความเว็บฮุคที่ได้รับจาก Discord ดึงข้อมูลรหัสผู้ใช้ ป้องกันการโจมตีแบบ replay
    ตามเวลาได้รับ และยืนยันลายเซ็น Roblox ด้วย secret ที่กำหนดเพื่อตรวจสอบความถูกต้อง
    """
    def parse_message(message):
    # วิเคราะห์ข้อความที่ได้รับสำหรับรหัสผู้ใช้และรหัสเกม
    if 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_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} is listening to Right to Erasure messages")
    """
    ตัวจัดการข้อความเว็บฮุคจาก Roblox
    """
    @client.event
    async def on_message(message):
    # วิเคราะห์และยืนยันข้อความ
    user_id, start_place_ids = message_parser.parse_message(message)
    if not user_id or not start_place_ids:
    return
    # ลบข้อมูลผู้ใช้จากที่เก็บข้อมูลแบบมาตรฐาน
    [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)}")
    # ลบข้อมูลผู้ใช้จากที่เก็บข้อมูลแบบจัดลำดับ
    [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()
  3. ในไฟล์ bot_config.py สำหรับการกำหนดค่าหลักของบอท:

    1. ตั้งค่า BOT_TOKEN เป็นโทเค็นที่สร้างโดยบอทของคุณ.
    2. ตั้งค่า OPEN_CLOUD_API_KEY เป็นคีย์ API ที่คุณสร้าง
    3. ตั้งค่า ROBLOX_WEBHOOK_SECRET เป็น secret ที่คุณตั้งค่าเมื่อกำหนดค่าเว็บฮุคใน Creator Dashboard
    4. ในพจนานุกรม STANDARD_DATA_STORE_ENTRIES และ ORDERED_DATA_STORE_ENTRIES เพื่อค้นหาที่เก็บข้อมูลของแต่ละระเบียนที่จะลบ:
      1. เพิ่ม Start Place ID ที่คุณคัดลอกเป็นกุญแจ
      2. เพิ่ม Universe ID เป็นองค์ประกอบแรกของค่า
      3. เปลี่ยนองค์ประกอบที่สองของทูเพิลเป็นชื่อ สโคป ชื่อคีย์เอนทรี และรหัสผู้ใช้ที่เกี่ยวข้องของที่เก็บข้อมูล หากคุณใช้สคีมข้อมูลที่แตกต่างกัน ให้ปรับเปลี่ยนให้ตรงกับสคีมข้อมูลของคุณเอง
  4. ประมวลผลคำสั่งต่อไปนี้เพื่อรันบอท:

    รัน Discord Bot

    python3 discord_bot.py
  5. บอทจะเริ่มฟังและตรวจสอบเว็บฮุคของ Roblox สำหรับคำขอสิทธิ์การลบและเรียกใช้ Open Cloud endpoint สำหรับการลบที่เก็บข้อมูลที่เกี่ยวข้อง

ทดสอบ

คุณสามารถสร้างและรันข้อความทดสอบเพื่อตรวจสอบว่าโปรแกรมกำหนดเองของคุณสามารถจัดการคำขอสิทธิ์การลบและลบข้อมูล PII ได้อย่างถูกต้อง:

  1. ส่งคำขอ HTTP POST ไปยังเซิร์ฟเวอร์เว็บฮุคของ Discord ของคุณด้วยเนื้อหาคำขอที่ตามนี้:

    ตัวอย่างคำขอ

    curl -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}"
    }
    }]
    }'
  2. หากคุณมีเว็บฮุค secret:

    1. สร้าง Roblox-Signature โดยใช้การเข้ารหัส HMAC-SHA256 กับคีย์เว็บฮุค secret ของคุณ
    2. ตั้งเวลาปัจจุบันเป็น Timestamp ในวินาทีตาม UTC
  3. รวบรวม description ในรูปแบบดังต่อไปนี้:

    รูปแบบฟิลด์คำอธิบาย

    {Timestamp}. You have received a new notification for Right to Erasure for the User Id: {userId} in the game(s) with Ids: {gameIds}`.

    ตัวอย่าง:

    ตัวอย่างฟิลด์คำอธิบาย

    1683927229. You have received a new notification for Right to Erasure for the User Id: 2425654247 in the game(s) with Ids: 10539205763, 13260950955

โปรแกรมของคุณควรสามารถระบุได้ว่าข้อความของคุณมาจากแหล่งที่มีอำนาจจาก Roblox เพราะคุณได้เข้ารหัสข้อความด้วย secret ของคุณ จึงควรลบข้อมูล PII ที่เกี่ยวข้องกับคำขอของคุณ

ตัวอย่างเนื้อหา

{
"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://create.roblox.com/dashboard/assets/webhooks/roblox_logo_metal.png",
"text": "Roblox-Signature: UIe6GJ78MHCmU/zUKBYP3LV0lAqwWRFR6UEfPt1xBFw=, Timestamp: 1683927229"
}
}
]
}
©2026 Roblox Corporation. Roblox, โลโก้ Roblox และ Powering Imagination เป็นส่วนหนึ่งของเครื่องหมายการค้าที่จดทะเบียน และไม่ได้จดทะเบียนของเราในสหรัฐฯ และประเทศอื่นๆ