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.
myPluginDonne accès à toutes les permissions de votre plugin.
myPlugin.commandsDonne accès à toutes les commandes de votre plugin.
myPlugin.commands.teleport.executeNe 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.allNe permet à l’utilisateur qu’à téléporter tous les joueurs d’un coup.
myPlugin.commands.teleport.worldsNe permet à l’utilisateur qu’à se téléporter aux différents mondes.
myPlugin.commands.teleport.worlds.mynetherworldNe 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 lesUsers 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’unSubjecten utilisant lesSubjects nommés. Les groupes doivent être utilisés si un sous-ensemble spécifique deSubjects 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 unCommandBlockuniquement 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);