Spring Security - @PreFilter et @PostFilter

Spring Security - @PreFilter et @PostFilter

1. Vue d'ensemble

Dans cet article, nous allons apprendre à utiliser les annotations@PreFilter et@PostFilter pour sécuriser les opérations dans une application Spring.

Lorsqu'ils sont utilisés avec les informations principales authentifiées,@PreFilter et@PostFilter nous permettent de définir des règles de sécurité affinées à l'aide de Spring Expression Language.

2. Présentation de@PreFilter et@PostFilter

En termes simples, les annotations@PreFilter et@PostFilter sontused to filter lists of objects basées sur des règles de sécurité personnalisées que nous définissons.

@PostFilter définit une règle de filtrage de la liste de retour d'une méthode, parapplying that rule to every element in the list. Si la valeur évaluée est true, l'élément sera conservé dans la liste. Sinon, l'élément sera supprimé.

@PreFilter fonctionne de manière très similaire, cependant, le filtrage est appliqué à une liste qui est passée en tant que paramètre d'entrée à la méthode annotée.

Les deux annotations peuvent être utilisées sur des méthodes ou des types (classes et interfaces). Nous les utiliserons uniquement sur les méthodes tout au long de cet article.

Ces annotations ne sont pas actives par défaut - nous devrons les activer avec l'annotation@EnableGlobalMethodSecurity etprePostEnabled = true - dans notre configuration de sécurité:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    // ...
}

3. Rédaction de règles de sécurité

Pour écrire les règles de sécurité dans ces deux annotations, nous utiliserons les expressions Spring-EL; nous pouvons également utiliser l'objet intégréfilterObject pour obtenir une référence à l'élément de liste particulier testé.

Spring Security fournit desmany other built-in objects pour créer des règles très spécifiques et exactes.

For example, nous pouvons utiliser@PreFilter pour vérifier si la propriétéassignee d'un objetTask est égale auxname de l'utilisateur actuellement authentifié:

@PostFilter("filterObject.assignee == authentication.name")
List findAll() {
    ...
}

Nous avons utilisé l'annotation@PostFilter ici car nous voulons que la méthode s'exécute et récupère toutes les tâches en premier, et ils transmettent chaque tâche de la liste à notre règle de filtrage.

Ainsi, si l'utilisateur authentifié estmichael, la liste finale des tâches renvoyées par la méthodefindAll ne contiendrait que les tâches affectées àmichael, même si la base de données a des tâches affectées à jim etpam.

Rendons maintenant la règle un peu plus intéressante. Supposons que si un utilisateur est un responsable, il peut voir toutes les tâches, peu importe à qui il est assigné:

@PostFilter("hasRole('MANAGER') or filterObject.assignee == authentication.name")
List findAll() {
    // ...
}

Nous avons utilisé la méthode intégréehasRole pour vérifier si l'utilisateur authentifié a le rôle de MANAGER. SihasRole renvoie vrai, la tâche sera conservée dans la liste finale. Ainsi, si l'utilisateur est un gestionnaire, la règle retournera la valeur true pour chaque élément de la liste. Ainsi, la liste finale contiendra tous les éléments.

Filtrons maintenant une liste passée en paramètre à une méthodesave en utilisant@PreFilter:

@PreFilter("hasRole('MANAGER') or filterObject.assignee == authentication.name")
Iterable save(Iterable entities) {
    // ...
}

La règle de sécurité est la même que celle que nous avons utilisée dans l'exemple@PostFilter. La principale différence ici est que les éléments de la liste seront filtrés avant l'exécution de la méthode, nous permettant ainsi de supprimer certains éléments de la liste, en empêchant leur enregistrement dans la base de données.

Ainsi,jim, qui n'est pas un gestionnaire, peut essayer de sauvegarder une liste de tâches, dont certaines sont affectées àpam. Cependant, seules les tâches assignées àjim seront incluses, les autres seront ignorées.

4. Performances sur de grandes listes

@PreFilter est vraiment cool et facile à utiliser, mais il peut être inefficace lorsqu'il s'agit de très grandes listes car l'opération de récupération récupérera toutes les données et appliquera le filtre par la suite.

Imaginons, par exemple, que nous ayons des milliers de tâches dans notre base de données et que nous voulions récupérer les cinq tâches actuellement assignées àpam. Si nous utilisons@PreFilter,, l'opération de base de données récupérera d'abord toutes les tâches et les parcourra toutes pour filtrer celles qui ne sont pas affectées àpam.

5. Conclusion

Cet article rapide explique comment créer une application simple mais sécurisée à l'aide des annotations@PreFilter et@PostFilter de Spring Security.

Consultez l'exemple de code completin this Github repository.