Permissions

Si vous êtes intéressé par les permissions utilisées par les commandes vanilla, consultez cette page. Pour modifier les niveaux de permission, référez-vous à la page des permissions serveur ou à la documentation de votre plugin.

Permission

Une permission est une chaîne de caractères hiérarchique, sensible à la casse, qui est utilisé pour déterminer si un sujet peut ou non effectuer une action. La chaîne de caractères est séparée en plusieurs parties, chacune séparée par point. Les permissions devraient être structurées comme ceci.

<PluginID>.<MainGroup>.<Subgroup1>...

Les caractères autorisés sont :

  • « A » - « Z »

  • « a » - « z »

  • « 0 » - « 9 »

  • « _ »

  • « - »

  • « . »

Héritage

Si un utilisateur a la permission myplugin.commands, automatiquement cet utilisateur disposera de toutes les sous permissions de celle-ci. Comme, par exemple, myplugin.commands.teleport à moins que cette permission ait été explicitement enlevée à l’utilisateur.

Note

Il n’y a pas de permission générique comme myplugin.commands.*, utilisez myplugin.commands pour cela.

Exemple de Structure

L’exemple ci-dessous montre une possibilité pour structurer vos permissions, mais cette structure n’est absolument pas obligatoire.

  • myplugin
    • Donne accès à toutes les permissions de votre plugin.

  • myplugin.commands
    • Donne accès à toutes les commandes de votre plugin.

  • myplugin.commands.teleport.execute
    • Ne permet à l’utilisateur qu’à exécuter la commande. Sans cette permission l’utilisateur n’est pas capable d’exécuter la commande même s’il dispose des autres permissions teleport. (Avec cette permission seule, l’utilisateur n’est capable que de se téléporter à d’autres utilisateurs dans son monde actuel.)

  • myplugin.commands.teleport.all
    • Ne permet à l’utilisateur qu’à téléporter tous les joueurs d’un coup.

  • myplugin.commands.teleport.worlds
    • Ne permet à l’utilisateur qu’à se téléporter aux différents mondes.

  • myplugin.commands.teleport.worlds.mynetherworld
    • Ne permet à l’utilisateur qu’à se téléporter à mynetherworld.

PermissionDescription

La PermissionDescription est un utilitaire qui permet de donner aux propriétaires de serveur une description sur une permission en particulier. La PermissionDescription est une fonctionnalité optionnelle qu’un PermissionService peut fournir. La création d’une PermissionDescription n’a aucun impact sur l’existence de la permission, qui y a accès et quelle est sa valeur par défaut.

La description comprend :

  • l’id de la permission en question

  • une description textuelle

  • un ou plusieurs rôles assignés

  • le plugin possesseur de cette permission

Si vous avez un élément dynamique comme un World ou un ItemType vous pouvez utiliser <TemplateParts>.

Exemple d’Utilisation

import org.spongepowered.api.service.permission.PermissionDescription;
import org.spongepowered.api.service.permission.PermissionDescription.Builder;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.text.Text;

PluginContainer plugin = ...;
Builder builder = permissionService.newDescriptionBuilder(plugin);

builder.id("myplugin.commands.teleport.execute")
       .description(Text.of("Allows the user to execute the teleport command."))
       .assign(PermissionDescription.ROLE_STAFF, true)
       .register();

Résultat Simple

myplugin.commands.teleport.execute

Description: Allows the user to execute the teleport command.
Role: user
Owner: MyPlugin v1.2.3

Résultat avec Template

myplugin.commands.teleport.worlds.<World>

Description: Allows the user to teleport to the world <World>.
Role: staff
Owner: MyPlugin v1.2.3

Astuce

Vous pouvez ignorer l’écriture des descriptions pour certains groupes de permissions parents tels que myplugin.commands.teleport.worlds ou myplugin.commands comme leur signification peut être déduite de la structure des permissions et seulement définir les permissions enfants.

Sujet

Un Subject est un détenteur de permissions. Il peut être obtenu depuis le PermissionService par l’intermédiaire de SubjectCollections. Les CommandSources comme les Players sont des Subjects par défaut, mais il y a beaucoup d’autres types de Subjects. Tout ce qui dispose d’une permission est un Sujet même si elle délègue simplement les contrôles à un Sujet contenu. Les permissions peuvent être accordées ou refusées à un Sujet. Si une permission n’est ni accordée ni refusée, ses paramètres seront hérités, voir la section sur l’héritage. Les Sujets donnent accès à des méthodes pour vérifier s’ils ont une certaine permission ou non. Les plugins qui utilisent cette méthode doivent uniquement demander les permissions spécifiques qu’ils veulent vérifier. C’est la tâche du PermissionService de respecter la permission et l’héritage de l’objet.

Exemple

L’exemple ci-dessous peut être utilisé pour vérifier si le Joueur est autorisé à exécuter la commande de téléportation.

import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.world.World;

public boolean canTeleport(Player subject, World targetWorld) {
    return subject.hasPermission("myplugin.command.teleport.execute")
            && (subject.getWorld() == targetWorld
                    || subject.hasPermission("myplugin.command.teleport." + targetWorld.getName()));
}

Héritage

Si un Subject possède une permission assignée, il utilisera cette valeur. Dans le cas contraire, la valeur sera héritée de n’importe quel Subject parent. Peu importe quel genre de Subject parent (comme un groupe ou un joueur.) il pourrait avoir.

Si ni le sujet lui-même, ni n’importe quel sujet parent n’accorde ou ne refuse la permission, alors il sera hérité des Subjects par défaut. Chaque SubjectCollection définit ses propres valeurs par défaut. Le sujet par défaut global le plus faible peut être obtenu depuis le PermissionService. Les plugins peuvent définir leurs propres permissions au SubjectData transitoire par défaut lors de chaque démarrage du serveur. Cela permet aux propriétaires du serveur de remplacer les valeurs par défaut définies par les plugins selon leurs besoins en utilisant le SubjectData persistant par défaut. Si vous voulez fournir une directive de configuration pour les propriétaires de serveurs, utilisez les rôle-modèles de PermissionDescription's à la place.

Avertissement

Vous devez y songer sérieusement avant d’accorder des permissions par défaut aux utilisateurs. En accordant des permissions en supposant que tous les propriétaires de serveurs vont vouloir ces valeurs par défaut (au moins la première fois que le plugin démarre) et que les exceptions nécessiteront que les propriétaires du serveur refusent explicitement les perrmissions (ce qui ne peut même pas être fait sans une implémentation d’un service de permissions personnalisées). Cela devrait correspondre en gros à un invité sur un monde lan en solo sans triche. Par exemple, un plugin de chat autoriserait à envoyer des messages dans le chat par défaut pour imiter le comportement du jeu de base pour des fonctionnalités qui ont été modifiées par le plugin.

Note

Les SubjectDatas persistants des Subjects prennent le dessus sur ceux qui sont transitoires. Pour tous les autres Subjects, les SubjectDatas transitoires prennent le dessus sur ceux qui sont persistants.

Si ni le Subject, ni aucun de ses parents, ni les valeurs par défaut n’assignent de valeur à une permission, alors elle est automatiquement refusée.

Note

Ordre de propriété dans l’ordre décroissant :

  • Le Subject lui-même
    • Transitoire

    • Persistant

  • Parents des Subjects
    • Transitoire

    • Persistant

  • Valeurs par défaut de SubjectCollection
    • Persistant

    • Transitoire

  • Valeurs par défaut de PermissionService
    • Persistant

    • Transitoire

  • Permission refusée

SubjectCollections

Un conteneur pour les sujets qui peut être utilisé pour obtenir un sujet par son nom. Voici les Subject Collections par défaut :

  • Utilisateur
    • Contient tous les Players connectés et les Users déconnectés (au moins ceux avec des paramètres qui ne sont pas ceux par défaut).

  • Groupe
    • Contient tous les groupes du Subject. Les groupes sont une façon simple de structures une arborescence d’héritage d’un Subject en utilisant les Subjects nommés. Les groupes doivent être utilisés si un sous-ensemble spécifique de Subjects possède des paramètres additionnels de permission comme une team, une faction, ou un rôle.

  • Système
    • Contient tous les autres Subjects utilisés par le serveur, comme la console et les possibles consoles distantes.

  • Bloc de Commande
    • Contient tous les Subjects pour les blocs de commande. Ils sont utiles si vous voulez exécuter un CommandBlock uniquement avec les permissions du créateur.

  • Modèle de Rôle
    • Contient tous les modèles de rôle qui sont utilisés dans les PermissionDescriptions. Utile pour rechercher toutes les permissions recommandées pour un utilisateur. Ils ne doivent pas être utilisés pour l’héritage.

Note

Quand des SubjectCollections sont demandés pour un Subject ils vont être créés automatiquement, si ils n’existent pas déjà. Cependant ils peuvent ne pas nécessairement apparaître dans getAllSubjects() sauf si des valeurs qui ne sont pas celles par défaut sont définies.

SubjectData

Les SubjectData sont les stockages des permissions actuelles connectées au sujet. Il y a deux types de stockages de sujet :

  • Transitoire = Dure seulement pendant la durée de la session, n’est jamais sauvegardé

  • Régulier (persistant) = Peut être sauvegardé quelquepart, et donc être persistant et exister pour toujours. Il est recommandé aux PermissionServices d’implémenter un stockage persistant, cependant ce n’est pas obligatoire. Il peut aussi dépendre du type du sujet. Si il n’y a aucune persistance alors le stockage transitoire sera retourné dans les deux méthodes.

Les auteurs de plugins devraient envisager si il est nécessaire ou non de faire persister une valeur au moment de choisir entre eux.

  • Si c’est seulement pour une courte période (par exemple pendant un minijeu), alors utilisez celui qui est transitoire.

  • Si c’est pour une longue période ou pour toujours (par exemple une promotion au VIP), utilisez celui qui est régulier (persistant).

Veuillez consulter la section héritage si vous voulez en savoir plus à propos de l’hérédité et la priorité des SubjectDatas transitoires et persistants.

Exemple

L’exemple suivant donne accorde une permission à un joueur dans le contexte global

import org.spongepowered.api.entity.living.player.Player;

public void setPermission(Player player, String permission) {
    if(!player.hasPermission(permission)
        player.getSubjectData().setPermission(SubjectData.GLOBAL_CONTEXT, permission, Tristate.TRUE);
}

Note

Dans l’exemple ci-dessus, Tristate.TRUE a été utilisé mais vous pouvez également utiliser Tristate.FALSE pour une interdire la permission et Tristate.UNDEFINED pour l’effacer complètement.

Options de Sujets

Les sujets fournissent aussi la possibilité de stocker des options en chaînes de caractères. Ce sont fondamentalement des pairs clé/valeur qui peuvent être assignés et hérités. Contrairement aux chaînes de caractères de permissions, les clés ne sont pas hiérarchiques et ne fournissent aucun mécanisme d’héritage eux-mêmes, mais les pairs clé/valeur eux-mêmes sont hérités des Subjects parents dans la même manière que les permissions.

Contextes

Si vous considérez chaque permission à un privilège ou une capacité à pouvoir faire quelque chose, un Context représente les circonstances où ce privilège est utilisable.

Vous pourriez vouloir donner quelque chose à faire à une permission de Subject, mais seulement lorsque le Subject est dans un certain monde, ou dans une certaine région.

Les contextes sont accumulés par un Subject, et sont alors utilisés par le PermissionService pour décider de si le Subject a un privilège ou non.

Sponge fournit quelques contextes par défaut, mais c’est généralement aux autres plugins de fournir des contextes additionnels au PermissionService, à travers un ContextCalculator.

Lors de la création de contextes pour vos propres pluginss, essayez d’éviter les conflits avec les autres plugins (par exemple en préfixant la clé de contexte avec l’id de votre plugin) à moins que ces contextes ne soient destinés à être partagés.

Note

Assurez-vous que votre ContextCalculator réponde le plus vite possible puisqu’il sera fréquemment appelé.

Avertissement

Les implémentations de ContextCalculator doivent être thread safe, parce qu’elles peuvent être appelées à partir d’en dehors du thread principal, ou même appelées en parallèle. Pour cette raison, tous les ContextCalculators non basés sur les noms ou non basés sur les uuid (comme ceux basés sur les locations) doivent utiliser un cache et doivent être mis à jour en utilisant des event listeners ou des schedulers synchronisés.

Exemple

Votre ContextCalculator peut ressembler à ceci :

import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.context.ContextCalculator;
import org.spongepowered.api.service.permission.Subject;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

public class ExampleCalculator implements ContextCalculator<Subject> {

    private static final Context IN_ANY_ARENA = new Context("myarenaplugin-inAnyArena", "true");
    private static final Context NOT_ANY_ARENA = new Context("myarenaplugin-inAnyArena", "false");
    private static final String ARENA_KEY = "myarenaplugin-arena";

    private final Map<UUID, String> playerArenas = new ConcurrentHashMap<>();

    @Override
    public void accumulateContexts(Subject subject, Set<Context> accumulator) {
        CommandSource commandSource = subject.getCommandSource().orElse(null);

        if (commandSource instanceof Player) {
            UUID uuid = ((Player) commandSource).getUniqueId();

            String arena = this.playerArenas.get(uuid);
            if (arena != null) {
                accumulator.add(IN_ANY_ARENA);
                accumulator.add(new Context(ARENA_KEY, arena));
            } else {
                accumulator.add(NOT_ANY_ARENA);
            }
        }
    }

    @Override
    public boolean matches(Context context, Subject subject) {
        CommandSource commandSource = subject.getCommandSource().orElse(null);

        if (commandSource instanceof Player) {
            UUID uuid = ((Player) commandSource).getUniqueId();

            if (context.equals(IN_ANY_ARENA)) {
                return this.playerArenas.containsKey(uuid);
            } else if (context.equals(NOT_ANY_ARENA)) {
                return !this.playerArenas.containsKey(uuid);
            } else if (context.getKey().equals(ARENA_KEY)) {
                return context.getValue().equals(this.playerArenas.get(uuid));
            }
        }

        return false;
    }

}

Le ContextCalculator peut être enregistré via :

permissionService.registerContextCalculator(contextCalculator);

Pour les Mods Forge

Si vous êtes l’auteur d’un mod Forge et que vous n’utilisez pas sa PermissionAPI mais faites à la place des vérifications de statut d’OP, alors vous êtes sur le bon chemin pour utiliser les permissions de Sponge.

La manière la plus simple de créer une permission Sponge dans un mod Forge sans soft-dépendance à SpongeAPI est d’utiliser la méthode fournie par Minecraft Vanilla dans ICommandSender nommée ICommandSender.canCommandSenderUseCommand(int permLevel, String commandName). Le String passé dans cette méthode n’a pas d’usage dans un environnement Forge Vanilla, mais quand SpongeForge est ajouté, il prend automatiquement le String et le convertit en une permission fonctionnelle.

Exemple

public class AwesomeBlock extends Block {
    @Override
    public boolean onBlockActivated(World world, BlockPos pos, IBlockState state,
            EntityPlayer player, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ) {
        if (player.canUseCommand(4, "examplemod.awesomeblock.interact")) {
            // Do cool stuff
            return true;
        }
        return false;
    }
}

Comme vous pouvez le voir, nous vérifions simplement le niveau d’OP et passons un String arbitraire que nous utiliserons comme permission quand Sponge est utilisé. Quand Forge Vanilla est utilisé, le joueur n’a besoin que du statut d’OP, donc passer une valeur de 0 permettrait aux utilisateurs d’interagir avec le bloc, mais quand SpongeForge est ajouté il devrait avoir la permission examplemod.awesomeblock.interact. Il est recommandé de suivre cette structure de permissions. L’héritage de permission s’applique à ces vérifications.

Note

Le nom SRG de cette méthode est func_70003_b.