2011-10-03 2 views
13

J'essaie de protéger un contrôleur avec l'annotation @PreAuthorize au niveau du type et d'essayer de contourner ce comportement en annotant certaines méthodes avec un @PreAuthorize différent. Le problème est cependant que Spring évalue d'abord l'annotation de la méthode (accorde l'accès) et évalue ensuite l'annotation de classe (refuse l'accès).Le paramètre @PreAuthorize de Spring Security au niveau du type ne peut pas être ignoré au niveau de la méthode

Y a-t-il un moyen d'inverser cet ordre? Je ne pouvais pas encore le comprendre.

Edit:

Sur le plan de la méthode, je veux accorder l'accès aux utilisateurs non enregistrés seulement:

@PreAuthorize("isAnonymous()") 
@RequestMapping(value = "/create", method = RequestMethod.GET) 
public String renderCreateEntity(ModelMap model) { 
    return userService.renderCreateEntity(model); 
} 

La norme pour ce contrôleur cependant, devrait être de permettre que les utilisateurs complètement authentifiés:

@Controller 
@RequestMapping(value = "/user") 
@PreAuthorize("isFullyAuthenticated()") 
public class UserController { [...] } 

Lorsque le débogage pas à pas à travers l'application, je vois que isAnonymous() est évalué d'abord, puis isFullyAuthenticated() entraînant ainsi dans une concession de droit d'accès et de refuser immédiatement l'accès à nouveau.

+0

Quelle version de Spring Security utilisez-vous? – beny23

+0

Tout le ressort est 3.0.5.RELEASE – chzbrgla

Répondre

11

Merci pour tous vos replys. La réponse cependant, était quelque chose de totalement différent :)

Je l'ai mis ici au cas où quelqu'un d'autre a les mêmes problèmes.

J'ai enregistré un validateur personnalisé dans une méthode annotée @InitBinder. Cette méthode de liaison est appelée APRES l'appel de méthode demandé sur le contrôleur. Et puisque cette méthode de liaison n'a pas été annotée avec @PreAuthorize, la demande a été refusée.

La solution était d'annoter la méthode de reliure comme ceci:

@InitBinder 
@PreAuthorize("permitAll") 
public void initBinder(WebDataBinder binder) { 
    binder.setValidator(validator); 
} 

Et puis, la méthode appelle de mon OP évalué comme prévu.

5

Le problème n'est pas que vous devez modifier l'ordre d'octroi et refuser. Le problème est simple que ces annotations de niveau de méthode annulent les annotations de niveau de classe.

PrePostAnnotationSecurityMetadataSource Java Doc:

Les annotations peuvent être spécifiées sur les classes ou les méthodes et les annotations spécifiques à la méthode seront prioritaires.

La mise en œuvre concrète de cette logique est effectuée dans la méthode findAnnotation de la classe PrePostAnnotationSecurityMetadataSource. (Malheureusement, cette méthode est privée.)

Donc, vous pouvez écrire votre propre MethodSecurityMetadataSource, si vous regardez le code de PrePostAnnotationSecurityMetadataSource, vous verrez comme c'est facile.

Mais un avertissement à la fin: la fin: tâche difficile ne réécrit pas la méthode, la tâche difficile consiste à "injecter" le nouveau MethodSecurityMetadataSource dans le système de sécurité. Je crois que vous ne pouvez pas le faire avec la configuration de l'espace de noms de sécurité de printemps, donc vous devez remplacer l'espace de noms de sécurité de printemps par une déclaration de bean explicite.

+0

En fait, _WANT_ l'annotation au niveau de la méthode pour remplacer l'annotation au niveau de la classe. Mais l'annotation au niveau de la méthode est évaluée en premier et en deuxième au niveau de la classe, de sorte que l'annotation au niveau de la classe remplace réellement l'annotation de la méthode. Je vais éditer un exemple dans ma question. – chzbrgla

+0

De mes tests, ce n'est plus vrai. Si vous disposez d'une annotation de sécurité au niveau de la classe et au niveau de la méthode (@Secured ou @PreAuthorized), ils sont tous deux exécutés. Si l'annotation au niveau de la méthode est plus restrictive, c'est très bien. Si c'est moins restrictif, ça ne marche pas. J'ai fini par scinder mes méthodes moins restrictives en un autre contrôleur. –

Questions connexes