Spring Security peut-il utiliser @PreAuthorize
sur les méthodes des contrôleurs Spring?
Oui, ça marche bien.
Vous avez besoin de <security:global-method-security pre-post-annotations="enabled" />
dans ...-servlet.xml
. Cela nécessite également les proxies CGLIB , donc soit vos contrôleurs ne devraient pas avoir d’interfaces, soit vous devriez utiliser proxy-target-class = true
.
Voir Spring Security FAQ (c'est moi qui souligne).
Dans une application Web Spring, contexte d'application contenant le fichier Les beans Spring MVC de la servlet de répartition sont souvent distincts de ceux du fichier contexte d'application principal. Il est souvent défini dans un fichier appelé myapp-servlet.xml, où «myapp» est le nom attribué à Spring DispatcherServlet dans web.xml. Une application peut avoir plusieurs DispatcherServlets, chacun avec son propre contexte d'application isolé . Les haricots dans ces contextes «enfants» ne sont pas visibles pour le reste du fichier application. Le contexte d'application «parent» est chargé par le fichier ContextLoaderListener que vous définissez dans votre web.xml et est visible par tous les contextes de l'enfant. Ce contexte parent est généralement celui où vous définissez votre configuration de sécurité, y compris le élément). Par conséquent, les contraintes de sécurité appliquées aux méthodes de ces haricots Web ne seront pas appliqués, car ils ne peuvent pas être vus à partir du contexte DispatcherServlet. Vous devez soit déplacer le déclaration dans le contexte Web ou déplacé le haricots que vous souhaitez sécuriser dans le contexte principal de l'application.
En général, nous recommandons d’appliquer la sécurité de la méthode au service couche plutôt que sur des contrôleurs Web individuels.
Si vous appliquez des raccourcis à la couche de service, vous devez uniquement définir <global-method-security>
dans le contexte de sécurité de votre application.
Si vous utilisez Spring 3.1, vous pouvez faire des choses plutôt cool avec ça. Jetez un oeil à https://github.com/mohchi/spring-security-request-mapping . Il s'agit d'un exemple de projet qui intègre @PreAuthorize avec RequestMappingHandlerMapping de Spring MVC afin que vous puissiez effectuer les opérations suivantes:
@RequestMapping("/")
@PreAuthorize("isAuthenticated()")
public String authenticatedHomePage() {
return "authenticatedHomePage";
}
@RequestMapping("/")
public String homePage() {
return "homePage";
}
Une demande de "/" appellera authentifiéHomePage () si l'utilisateur est authentifié. Sinon, il appellera homePage ().
Cela fait plus de deux ans que cette question a été posée, mais à cause des problèmes que j'ai rencontrés aujourd’hui, je préfère décourager d’utiliser @Secured
, @PreAuthorize
, etc. sur @Controller
s.
Ce qui n'a pas fonctionné pour moi, c'est @Validated
combiné avec le contrôleur @Secured
:
@Controller
@Secured("ROLE_ADMIN")
public class AdministrationController {
// @InitBinder here...
@RequestMapping(value = "/administration/add-product", method = RequestMethod.POST)
public String addProductPost(@ModelAttribute("product") @Validated ProductDto product, BindingResult bindingResult) {
// ...
}
Validator ne se déclenche tout simplement pas (Spring MVC 4.1.2, Spring Security 3.2.5) et aucun contrôle n’est effectué.
Des problèmes similaires sont causés par les proxies CGLIB utilisés par Spring (lorsqu'aucune interface n'est implémentée par une classe, Spring crée un proxy CGLIB; si la classe implémente une interface, le proxy JDK est généré - documentation , puits expliqué ici et ici ).
Comme indiqué dans les réponses que j'ai liées ci-dessus, il n'est pas préférable d'utiliser les annotations Spring Security sur la couche de service qui implémente généralement des interfaces (les mandataires JDK sont donc utilisés), car cela ne conduit pas à de tels problèmes.
Si vous souhaitez sécuriser les contrôleurs Web, la meilleure idée consiste à utiliser <http>
et <intercept-url />
qui sont liés à des URL spécifiques plutôt qu'aux méthodes des contrôleurs et fonctionnent plutôt bien. Dans mon cas:
<http use-expressions="true" disable-url-rewriting="true">
...
<intercept-url pattern="/administration/**" access="hasRole('ROLE_ADMIN')" />
</http>
Il existe déjà une réponse sur la façon de le faire fonctionner en modifiant la configuration xml; Toutefois, si vous travaillez avec une configuration basée sur un code, vous pouvez obtenir le même résultat en plaçant l'annotation suivante sur votre classe @Configuration
:
@EnableGlobalMethodSecurity(prePostEnabled=true)
Pour étendre la réponse fournie par Andy, vous pouvez utiliser:
@PreAuthorize("hasRole('foo')")
pour vérifier le rôle spécifique.
Vous devez d’abord ajouter cette annotation à votre WebSecurityConfig pour activer les annotations @Pre et @Post.
@EnableGlobalMethodSecurity(prePostEnabled = true)
Vous pouvez également vérifier les rôles/autorités comme suit
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
équivalent à
@PreAuthorize("hasRole('ROLE_ADMIN')")
Vous pouvez également vérifier plusieurs rôles/autorités comme suit
@PreAuthorize("hasAuthority('ROLE_ADMIN') or hasAuthority('ROLE_USER') or ...")