282 votes

Lorsque vous utilisez Spring Security, quelle est la bonne façon d’obtenir des informations de nom d’utilisateur (c.-à-d. SecurityContext) actuel dans un bean ?

J’ai une application de web de Spring MVC qui utilise la sécurité de printemps. Je veux savoir le nom d’utilisateur de l’utilisateur actuellement connecté. L’extrait de code ci-dessous, c’est ce que je fais. Ma question est, est-ce la façon ?

Je n’aime pas avoir un appel à une méthode statique à l’intérieur de ce contrôleur - qui défait le but entier de printemps, mon humble avis. Est-il possible de configurer l’application pour que l’actuel SecurityContext ou authentification actuelle, injecté à la place ?

253voto

tsunade21 Points 1612

Si vous utilisez Spring 3 le plus simple est :

65voto

Scott Bale Points 4385

Beaucoup de choses ont changé dans le Ressort du monde depuis que cette question a été répondu. Le printemps a simplifié l'obtention de l'utilisateur actuel dans un contrôleur. Pour d'autres haricots, le Printemps a adopté les suggestions de l'auteur et simplifiée de l'injection de "SecurityContextHolder'. Plus de détails dans les commentaires.


C'est la solution que j'ai fini par aller avec. Au lieu d'utiliser SecurityContextHolder dans mon contrôleur, je veux injecter quelque chose qui utilise SecurityContextHolder sous le capot, mais les résumés de suite que singleton-comme la classe de mon code. J'ai trouvé aucun moyen pour ce faire d'autre que de rouler ma propre interface, comme suit:

public interface SecurityContextFacade {

  SecurityContext getContext();

  void setContext(SecurityContext securityContext);

}

Maintenant, mon contrôleur (ou quel que soit POJO) devrait ressembler à ceci:

public class FooController {

  private final SecurityContextFacade securityContextFacade;

  public FooController(SecurityContextFacade securityContextFacade) {
    this.securityContextFacade = securityContextFacade;
  }

  public void doSomething(){
    SecurityContext context = securityContextFacade.getContext();
    // do something w/ context
  }

}

Et, à cause de l'interface est un point de découplage, l'unité de test est simple. Dans cet exemple, j'utilise Mockito:

public class FooControllerTest {

  private FooController controller;
  private SecurityContextFacade mockSecurityContextFacade;
  private SecurityContext mockSecurityContext;

  @Before
  public void setUp() throws Exception {
    mockSecurityContextFacade = mock(SecurityContextFacade.class);
    mockSecurityContext = mock(SecurityContext.class);
    stub(mockSecurityContextFacade.getContext()).toReturn(mockSecurityContext);
    controller = new FooController(mockSecurityContextFacade);
  }

  @Test
  public void testDoSomething() {
    controller.doSomething();
    verify(mockSecurityContextFacade).getContext();
  }

}

L'implémentation par défaut de l'interface ressemble à ceci:

public class SecurityContextHolderFacade implements SecurityContextFacade {

  public SecurityContext getContext() {
    return SecurityContextHolder.getContext();
  }

  public void setContext(SecurityContext securityContext) {
    SecurityContextHolder.setContext(securityContext);
  }

}

Et, enfin, la production de Printemps de config ressemble à ceci:

<bean id="myController" class="com.foo.FooController">
     ...
  <constructor-arg index="1">
    <bean class="com.foo.SecurityContextHolderFacade">
  </constructor-arg>
</bean>

Il semble de plus qu'un peu idiot que le Printemps, un conteneur d'injection de dépendances de toutes choses, n'a pas fourni un moyen d'injecter quelque chose de similaire. Je comprends SecurityContextHolder a été hérité d'acegi, mais tout de même. La chose est, ils sont si proches - si seulement SecurityContextHolder avaient un getter pour obtenir le sous-jacent SecurityContextHolderStrategy instance (qui est une interface), vous pouvez injecter. En fait, j'ai même ouvert un Jira problème à cet effet.

Une dernière chose: j'ai juste changé de façon substantielle la réponse que j'ai eu ici avant. Vérifier l'historique si vous êtes curieux, mais, comme un collègue me l'a fait remarquer, ma précédente réponse ne serait pas travailler dans un environnement multi-thread. Le sous-jacent SecurityContextHolderStrategy utilisée par SecurityContextHolder est, par défaut, une instance de ThreadLocalSecurityContextHolderStrategy, qui stocke SecurityContexts en ThreadLocal. Par conséquent, il n'est pas forcément une bonne idée d'injecter de l' SecurityContext directement d'une fève à l'initialisation de temps, il faudra peut-être récupéré à partir de l' ThreadLocal chaque fois que, dans un environnement multi-thread, donc la bonne l'un est extrait.

22voto

matt b Points 73770

Je suis d’accord que devoir interroger SecurityContext pour la PUE de l’utilisateur actuel, il semble une manière très non-printemps pour traiter ce problème.

J’ai écrit une classe statique « helper » pour faire face à ce problème ; C’est sale car il s’agit d’une méthode globale et statique, mais j’ai pensé que cette façon si nous changeons tout ce qui touche à la sécurité, au moins je n’ai que de modifier les détails en un seul endroit :

21voto

Brad Parks Points 5513

Pour faire il suffit de se présenter dans les pages JSP, vous pouvez utiliser le Printemps de Sécurité Tag Lib:

http://static.springsource.org/spring-security/site/docs/3.0.x/reference/taglibs.html

Pour utiliser toutes les balises, vous devez avoir la sécurité taglib déclaré dans votre JSP:

<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %>

Puis dans une page jsp faire quelque chose comme ceci:

<security:authorize access="isAuthenticated()">
    logged in as <security:authentication property="principal.username" /> 
</security:authorize>

<security:authorize access="! isAuthenticated()">
    not logged in
</security:authorize>

REMARQUE: Comme indiqué dans les commentaires de @SBerg413, vous aurez besoin d'ajouter

utilisez-les expressions="true"

pour le "http" dans la balise security.xml config pour que cela fonctionne.

13voto

digz6666 Points 1109

Je reçois un utilisateur authentifié par HttpServletRequest.getUserPrincipal() ;

Exemple :

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X