Permissions

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;
import java.util.Optional;

Optional<Builder> optBuilder = permissionService.newDescriptionBuilder(myPlugin);
if (optBuilder.isPresent()) {
    Builder builder = optBuilder.get();
    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 parent tel 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.

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é.

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.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

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 HashMap<>();

    @Override
    public void accumulateContexts(Subject calculable, Set<Context> accumulator) {
        final Optional<CommandSource> commandSource = calculable.getCommandSource();

        if (commandSource.isPresent() && commandSource.get() instanceof Player) {
            final Player player = (Player) commandSource.get();

            final UUID uuid = player.getUniqueId();
            if (this.playerArenas.containsKey(uuid)) {
                accumulator.add(IN_ANY_ARENA);
                accumulator.add(new Context(ARENA_KEY, this.playerArenas.get(uuid)));
            } else {
                accumulator.add(NOT_ANY_ARENA);
            }
        }
    }

    @Override
    public boolean matches(Context context, Subject subject) {
        if (!context.equals(IN_ANY_ARENA) && !context.equals(NOT_ANY_ARENA) && !context.getKey().equals(ARENA_KEY)) {
            return false;
        }

        final Optional<CommandSource> commandSource = subject.getCommandSource();
        if (!commandSource.isPresent() || !(commandSource.get() instanceof Player)) {
            return false;
        }

        final Player player = (Player) commandSource.get();

        if (context.equals(IN_ANY_ARENA) && !this.playerArenas.containsKey(player.getUniqueId())) {
            return false;
        }

        if (context.equals(NOT_ANY_ARENA) && this.playerArenas.containsKey(player.getUniqueId())) {
            return false;
        }

        if (context.getKey().equals(ARENA_KEY)) {
            if (!this.playerArenas.containsKey(player.getUniqueId())) {
                return false;
            }

            if (!this.playerArenas.get(player.getUniqueId()).equals(context.getValue())) {
                return false;
            }
        }

        return true;
    }
}

Le ContextCalculator peut être enregistré via :

permissionService.registerContextCalculator(contextCalculator);