Retour au cours

games / fivem

Commandes & permissions : RegisterCommand, ACE

Leçon 81 exercice

Explication

Ce que vous allez apprendre

  • Créer une commande avec RegisterCommand et lire ses arguments
  • Comprendre le principe des ACE (Access Control Entries) : groupes, permissions, identifiants
  • Restreindre une commande sensible avec le flag restricted de RegisterCommand
  • Vérifier une permission manuellement dans le code avec IsPlayerAceAllowed
  • Journaliser les tentatives refusées pour repérer les abus

Dans quel contexte ?

Un serveur RP doit permettre à ses administrateurs d'exécuter des commandes comme /kick ou /givemoney, tout en interdisant absolument ces mêmes commandes à un joueur ordinaire. Sans système de permissions structuré, chaque développeur finirait par réinventer sa propre vérification, souvent incomplète — les ACE de FiveM offrent un mécanisme standard, éprouvé, pour éviter ce problème.

ÉlémentRôle
add_ace group.admin command.kick allowAttribue une permission à un groupe
add_principal identifier.license:... group.adminAjoute un joueur à un groupe
RegisterCommand(..., true)Restreint la commande aux joueurs autorisés par ACE

Piège fréquent

Vérifier une permission uniquement côté client (par exemple cacher un bouton "Kick" dans une UI) ne protège rien : un joueur peut toujours déclencher directement l'event ou la commande serveur correspondante. La vérification de permission doit toujours avoir lieu côté serveur.

Un point d'entrée simple, mais sensible

Une commande tapée dans le chat ou la console (/tp, /kick) est souvent la façon la plus rapide de déclencher une action côté serveur. Mais certaines de ces actions — bannir un joueur, donner de l'argent — ne doivent évidemment pas être accessibles à tout le monde. FiveM fournit un système de permissions intégré pour encadrer cela, plutôt que de laisser chaque développeur réinventer sa propre solution de vérification.

ACE : comprendre le principe avant la syntaxe

ACE (Access Control Entries) fonctionne sur un principe simple, hérité du monde des systèmes d'exploitation : on définit des groupes (comme "admin"), on leur attribue des permissions précises (comme le droit d'utiliser la commande kick), puis on ajoute des joueurs à ces groupes en les identifiant par un identifiant unique et stable (comme leur licence Rockstar). Un joueur hérite alors automatiquement de toutes les permissions de tous les groupes auxquels il appartient.

Le flag "restricted" de RegisterCommand

Le deuxième argument de RegisterCommand (true ou false) indique si FiveM doit lui-même vérifier automatiquement la permission ACE correspondante avant même d'exécuter le code de la commande. Avec true, un joueur sans la permission ne verra même pas son code s'exécuter — la vérification a lieu en amont, de façon transparente.

Pourquoi vérifier manuellement, parfois

Le flag ACE natif reste binaire (autorisé ou non). Pour des logiques plus fines (par exemple, autoriser une action seulement à certaines heures, ou avec des conditions supplémentaires), on peut appeler IsPlayerAceAllowed directement dans le code, en combinant la vérification ACE avec sa propre logique métier.

Le réflexe à prendre : logger les refus

Enregistrer chaque tentative refusée par manque de permission (comme montré avec print('[SECURITY] ...')) donne une trace précieuse pour repérer des joueurs qui testent délibérément les limites du système — une pratique reprise et approfondie dans la leçon sur la sécurité.

Commandes & code

Commandes & permissions

Les commandes chat/console sont un point d'entrée courant pour les fonctionnalités admin ou joueur.

lua
-- Commande simple accessible à tous
RegisterCommand('tp', function(source, args, rawCommand)
    local src = source
    if src == 0 then return end -- 0 = console serveur, pas un joueur en jeu

    local x, y, z = tonumber(args[1]), tonumber(args[2]), tonumber(args[3])
    if not x or not y or not z then
        TriggerClientEvent('chat:addMessage', src, { args = { 'Usage: /tp x y z' } })
        return
    end

    local ped = GetPlayerPed(src)
    SetEntityCoords(ped, x, y, z, false, false, false, true)
end, false) -- false = commande NON restreinte par ACE
lua
-- Commande sensible, restreinte par permission ACE
RegisterCommand('kick', function(source, args)
    local target = tonumber(args[1])
    if target then
        DropPlayer(target, 'Kick administrateur')
    end
end, true) -- true = restreint : nécessite une permission ACE pour être exécutée
ini
; server.cfg : déclaration des groupes et permissions ACE
add_ace group.admin command.kick allow
add_ace group.admin command.givemoney allow
add_principal identifier.license:7c9c0e4c9f3a... group.admin
lua
-- Vérification manuelle de permission dans le code (ex: hors commande)
local function IsPlayerAdmin(source)
    return IsPlayerAceAllowed(source, 'command.kick')
end

RegisterCommand('givemoney', function(source, args)
    if not IsPlayerAdmin(source) then
        print(('[SECURITY] %s a tenté /givemoney sans permission'):format(source))
        return
    end

    local target = tonumber(args[1])
    local amount = tonumber(args[2])
    if not target or not amount then return end

    AddMoneyToPlayer(target, amount)
end, false) -- restriction gérée manuellement plutôt que par le flag ACE natif
ÉlémentRôle
add_aceattribue une permission à un groupe
add_principalajoute un joueur (par identifiant) à un groupe
RegisterCommand(..., true)restreint la commande aux joueurs ayant la permission ACE
IsPlayerAceAllowedvérification manuelle d'une permission dans le code Lua

Résumé

  • Ne jamais faire confiance à une vérification de permission faite côté client.
  • Le flag restricted de RegisterCommand s'appuie directement sur le système ACE de server.cfg.
  • Logger les tentatives refusées aide à détecter les abus/exploits en production.

Exercices pratiques

1 disponible
1

Mission : le bouton admin qui ne protège rien

Objectif : Corriger une commande sensible protégée uniquement par une interface, et la sécuriser avec ACE et logging.

Contexte

Le serveur affiche un bouton "Donner de l'argent" uniquement dans l'interface des joueurs marqués admin côté client (if isAdminUI then showButton() end). La commande serveur réelle, elle, ressemble à :

lua
RegisterCommand('givemoney', function(source, args)
    AddMoneyToPlayer(tonumber(args[1]), tonumber(args[2]))
end, false)

Un joueur non-admin a découvert qu'il pouvait taper /givemoney directement dans le chat, sans passer par aucun bouton, et se créditer de l'argent à volonté.

Résoudre l’exercice →