J'ai une application Web Spring MVC qui utilise Spring Security. Je veux connaître le nom d'utilisateur de l'utilisateur actuellement connecté. J'utilise l'extrait de code ci-dessous. Est-ce la voie acceptée?
Je n'aime pas avoir un appel à une méthode statique à l'intérieur de ce contrôleur - qui va à l'encontre du but de Spring, à mon humble avis. Existe-t-il un moyen de configurer l'application pour que le SecurityContext actuel ou l'authentification actuelle soit injecté à la place?
@RequestMapping(method = RequestMethod.GET)
public ModelAndView showResults(final HttpServletRequest request...) {
final String currentUser = SecurityContextHolder.getContext().getAuthentication().getName();
...
}
java
spring
spring-mvc
spring-security
Scott Bale
la source
la source
Réponses:
Si vous utilisez Spring 3 , la manière la plus simple est:
la source
Beaucoup de choses ont changé dans le monde du printemps depuis la réponse à cette question. Spring a simplifié le placement de l'utilisateur actuel dans un contrôleur. Pour les autres beans, Spring a adopté les suggestions de l'auteur et simplifié l'injection de 'SecurityContextHolder'. Plus de détails sont dans les commentaires.
C'est la solution avec laquelle j'ai fini par aller. Au lieu d'utiliser
SecurityContextHolder
dans mon contrôleur, je veux injecter quelque chose qui utiliseSecurityContextHolder
sous le capot mais qui résume cette classe de type singleton de mon code. Je n'ai trouvé aucun autre moyen que de rouler ma propre interface, comme ceci:Maintenant, mon contrôleur (ou n'importe quel POJO) ressemblerait à ceci:
Et, comme l'interface est un point de découplage, le test unitaire est simple. Dans cet exemple, j'utilise Mockito:
L'implémentation par défaut de l'interface ressemble à ceci:
Et, enfin, la configuration de production de Spring ressemble à ceci:
Il semble plus qu'un peu stupide que Spring, un conteneur d'injection de dépendance de toutes choses, n'a pas fourni un moyen d'injecter quelque chose de similaire. Je comprends que a
SecurityContextHolder
été hérité d'Acegi, mais quand même. Le fait est qu'ils sont si proches - si seulementSecurityContextHolder
un getter pouvait obtenir l'SecurityContextHolderStrategy
instance sous-jacente (qui est une interface), vous pourriez l'injecter. En fait, j'ai même ouvert un dossier Jira à cet effet.Une dernière chose - je viens de changer considérablement la réponse que j'avais ici auparavant. Consultez l'historique si vous êtes curieux mais, comme un collègue me l'a fait remarquer, ma réponse précédente ne fonctionnerait pas dans un environnement multi-thread. Le sous-jacent
SecurityContextHolderStrategy
utilisé parSecurityContextHolder
est, par défaut, une instance deThreadLocalSecurityContextHolderStrategy
, qui stockeSecurityContext
s dans aThreadLocal
. Par conséquent, ce n'est pas nécessairement une bonne idée d'injecter leSecurityContext
directement dans un bean au moment de l'initialisation - il peut être nécessaire de le récupérer àThreadLocal
chaque fois, dans un environnement multi-thread, afin que le bon soit récupéré.la source
Je suis d'accord que devoir interroger le SecurityContext pour l'utilisateur actuel pue, cela semble être un moyen très anti-Spring pour gérer ce problème.
J'ai écrit une classe "d'aide" statique pour résoudre ce problème; c'est sale dans la mesure où c'est une méthode globale et statique, mais j'ai pensé de cette façon si nous changeons quelque chose lié à la sécurité, au moins je n'ai qu'à changer les détails en un seul endroit:
la source
Pour le faire apparaître simplement dans vos pages JSP, vous pouvez utiliser la Librairie de balises de sécurité Spring:
http://static.springsource.org/spring-security/site/docs/3.0.x/reference/taglibs.html
Pour utiliser l'une des balises, vous devez déclarer la balise de sécurité dans votre JSP:
Ensuite, dans une page jsp, faites quelque chose comme ceci:
REMARQUE: Comme mentionné dans les commentaires de @ SBerg413, vous devrez ajouter
à la balise "http" dans la configuration security.xml pour que cela fonctionne.
la source
Si vous utilisez Spring Security ver> = 3.2, vous pouvez utiliser l'
@AuthenticationPrincipal
annotation:Voici
CustomUser
un objet personnalisé qui implémenteUserDetails
qui est retourné par une coutumeUserDetailsService
.Plus d'informations peuvent être trouvées dans le chapitre @AuthenticationPrincipal des documents de référence de Spring Security.
la source
J'obtiens l'utilisateur authentifié par HttpServletRequest.getUserPrincipal ();
Exemple:
la source
null
si l'utilisateur est authentifié de manière anonyme (http
>anonymous
éléments dans Spring Security XML).SecurityContextHolder
ouSecurityContextHolderStrategy
est la bonne façon.Au printemps 3+, vous avez les options suivantes.
Option 1 :
Option 2 :
Option 3:
Option 4: Fantaisie: consultez cette option pour plus de détails
la source
@CurrentUser
ce qui fonctionne comme la coutume@ActiveUser
de votre lien.@AuthenticationPrincipal
avec une@CurrentUser
annotation personnalisée . Depuis 3.2, nous n'avons pas besoin d'implémenter un résolveur d'arguments personnalisé comme dans la réponse liée. Cette autre réponse a plus de détails.Oui, la statique est généralement mauvaise - généralement, mais dans ce cas, la statique est le code le plus sécurisé que vous puissiez écrire. Étant donné que le contexte de sécurité associe un principal au thread en cours d'exécution, le code le plus sécurisé accéderait au statique à partir du thread aussi directement que possible. Masquer l'accès derrière une classe wrapper qui est injectée fournit à un attaquant plus de points à attaquer. Ils n'auraient pas besoin d'accéder au code (qu'ils auraient du mal à changer si le pot était signé), ils ont juste besoin d'un moyen de remplacer la configuration, ce qui peut être fait au moment de l'exécution ou en glissant du XML sur le chemin de classe. Même l'utilisation de l'injection d'annotations dans le code signé serait remplaçable avec du XML externe. Un tel XML pourrait injecter le système en cours d'exécution avec un principal escroc.
la source
Je voudrais juste faire ceci:
la source
SecurityContextHolderAwareRequestFilter
qui enveloppe la demande et implémente cet appel en accédant àSecurityContextHolder
.Pour la dernière application Spring MVC que j'ai écrite, je n'ai pas injecté le support SecurityContext, mais j'avais un contrôleur de base sur lequel j'avais deux méthodes utilitaires liées à cela ... isAuthenticated () & getUsername (). En interne, ils font l'appel de méthode statique que vous avez décrit.
Au moins, il n'est en place qu'une seule fois si vous avez besoin d'un remaniement ultérieur.
la source
Vous pouvez utiliser l'approche Spring AOP. Par exemple, si vous avez un service, il doit connaître le principal actuel. Vous pouvez introduire une annotation personnalisée, c'est-à-dire @Principal, qui indique que ce service doit être dépendant du principal.
Ensuite, dans votre conseil, qui, je pense, doit étendre MethodBeforeAdvice, vérifiez que le service particulier a une annotation @Principal et injectez le nom principal, ou définissez-le sur 'ANONYMOUS' à la place.
la source
Le seul problème est que même après l'authentification avec Spring Security, le bean utilisateur / principal n'existe pas dans le conteneur, donc l'injection de dépendances sera difficile. Avant d'utiliser Spring Security, nous créions un bean à portée de session qui avait le principal actuel, l'injections dans un "AuthService", puis injections ce service dans la plupart des autres services de l'application. Donc, ces services appellent simplement authService.getCurrentUser () pour obtenir l'objet. Si vous avez un endroit dans votre code où vous obtenez une référence au même principal dans la session, vous pouvez simplement le définir comme une propriété sur votre bean à portée de session.
la source
Essaye ça
la source
La meilleure solution si vous utilisez Spring 3 et avez besoin du principal authentifié dans votre contrôleur est de faire quelque chose comme ceci:
la source
J'utilise l'
@AuthenticationPrincipal
annotation dans les@Controller
classes ainsi que dans les classes@ControllerAdvicer
annotées. Ex.:Où
UserActive
est la classe que j'utilise pour les services des utilisateurs connectés, et s'étend deorg.springframework.security.core.userdetails.User
. Quelque chose comme:Vraiment facile.
la source
Définissez
Principal
comme dépendance dans votre méthode de contrôleur et Spring injectera l'utilisateur authentifié actuel dans votre méthode lors de l'invocation.la source
J'aime partager ma façon de prendre en charge les détails de l'utilisateur sur la page de marque de commerce Tout est très simple et fonctionne parfaitement!
Il vous suffit de placer une nouvelle demande d'authentification sur
default-target-url
(page après la connexion au formulaire). Voici ma méthode Controler pour cette page:Et voici mon code ftl:
Et c'est tout, le nom d'utilisateur apparaîtra sur chaque page après autorisation.
la source