web-dev-qa-db-fra.com

Spring MVC - Vérification si l'utilisateur est déjà connecté via Spring Security?

J'ai une application Spring MVC. Il utilise sa propre page de connexion personnalisée . Une fois la connexion réussie, un objet 'LOGGED_IN_USER' est placé dans HTTPSession.

Je souhaite autoriser uniquement les utilisateurs authentifiés à accéder aux URL. Je sais que je peux y parvenir en utilisant un filtre Web. Mais, cette partie que je veux faire avec Spring Security (mon chèque restera le même - cherchez l’objet 'LOGGED_IN_USER' dans HTTPSession, si vous êtes présent, vous êtes connecté).

Ma contrainte est que je ne peux pas changer le comportement de connexion à l'heure actuelle - cela n'utilisera pas encore Spring Security.

Quel aspect de Spring Security puis-je utiliser pour réaliser cette partie seul - vérifier si la demande est authentifiée (par l'utilisateur connecté)?  

39
Jasper

Il y a au moins 4 manières différentes:

configuration XML de sécurité de printemps

c'est le moyen le plus simple

<security:http auto-config="true" use-expressions="true" ...>
   ...
  <security:intercept-url pattern="/forAll/**" access="permitAll" />
  <security:intercept-url pattern="/**" access="isAuthenticated()" />
</security:http>

Par annotation sécurisée

nécessite <global-method-security secured-annotations="enabled" />

@Secured("ROLE_ADMIN")
@RequestMapping(params = "onlyForAdmins")    
public ModelAndView onlyForAdmins() {
    ....
}

Annotation @PreAuthorize

nécessite <global-method-security pre-post-annotations="enabled" />

 @PreAuthorize("isAuthenticated()")
 @RequestMapping(params = "onlyForAuthenticated")
 public ModelAndView onlyForAuthenticatedUsers() {
     ....
 }

Programmatique

 SecurityContextHolder.getContext().getAuthentication() != null &&
 SecurityContextHolder.getContext().getAuthentication().isAuthenticated() &&
 //when Anonymous Authentication is enabled
 !(SecurityContextHolder.getContext().getAuthentication() 
          instanceof AnonymousAuthenticationToken) 

Expression personnalisée

Si les expressions intégrées ne suffisent pas, vous pouvez les développer. Comment étendre les expressions SpEL pour les annotations de méthode est discuté par exemple ici:

Mais pour l'intercepteur <security:intercept-url ... access="myCustomAuthenticatedExpression" />, une approche légèrement différente est possible, il n'est pas nécessaire de traiter le problème de la classe privée. - Je ne l'ai fait que pour Spring Security 3.0, mais j'espère que cela fonctionnera aussi pour 3.1.}

1.) vous devez créer une nouvelle classe qui s'étend de WebSecurityExpressionRoot (le préfixe Web est la partie importante!).

public class MyCustomWebSecurityExpressionRoot
         extends WebSecurityExpressionRoot {
     public MyCustomWebSecurityExpressionRoot(Authentication a,
                 FilterInvocation f) {
          super(a, f);
     }

     /** That method is the one that does the expression evaluation! */
     public boolean myCustomAuthenticatedExpression() {
        return super.request.getSession().getValue("myFlag") != null;
     }
}

2.) vous avez besoin d’une extension de la DefaultWebSecurityExpressionRootHandler pour disposer d’un gestionnaire fournissant votre expression personnalisée root

 public class MyCustomWebSecurityExpressionHandler
              extends DefaultWebSecurityExpressionHandler {

      @Override        
      public EvaluationContext createEvaluationContext(Authentication a,
                FilterInvocation f) {
          StandardEvaluationContext ctx =
                   (StandardEvaluationContext) super.createEvaluationContext(a, f);

           WebSecurityExpressionRoot myRoot =
                    new MyCustomWebSecurityExpressionRoot(a, f);

           ctx.setRootObject(myRoot);
           return ctx;
      }
 }

3.) Ensuite, vous devez enregistrer votre gestionnaire auprès des électeurs

<security:http use-expressions="true"
 access-decision-manager-ref="httpAccessDecisionManager" ...>
      ...
    <security:intercept-url pattern="/restricted/**"
              access="myCustomAuthenticatedExpression" />         
      ...
</security:http>

<bean id="httpAccessDecisionManager"
      class="org.springframework.security.access.vote.AffirmativeBased">
    <constructor-arg name="decisionVoters">
            <list>
                <ref bean="webExpressionVoter" />
            </list>
    </constructor-arg>
</bean>

<bean id="webExpressionVoter"
      class="org.springframework.security.web.access.expression.WebExpressionVoter">
    <property name="expressionHandler"
              ref="myCustomWebSecurityExpressionHandler" />
</bean>

<bean id="myCustomWebSecurityExpressionHandler"
    class="MyCustomWebSecurityExpressionHandler" />

Spring Security 3.1 Update

Depuis Spring Security 3.1, il est un peu plus facile d'implémenter une expression personnalisée. Il n'est plus nécessaire de sous-classer WebSecurityExpressionHandler et de remplacer createEvaluationContext. Au lieu de cela, une sous-classe AbstractSecurityExpressionHandler<FilterInvocation> ou sa sous-classe DefaultWebSecurityExpressionHandler et outrepasse SecurityExpressionOperations createSecurityExpressionRoot(final Authentication a, final FilterInvocation f).

 public class MyCustomWebSecurityExpressionHandler
              extends DefaultWebSecurityExpressionHandler {

      @Override        
      public SecurityExpressionOperations createSecurityExpressionRoot(
                Authentication a,
                FilterInvocation f) {
           WebSecurityExpressionRoot myRoot =
                    new MyCustomWebSecurityExpressionRoot(a, f);

           myRoot.setPermissionEvaluator(getPermissionEvaluator());
           myRoot.setTrustResolver(this.trustResolver);
           myRoot.setRoleHierarchy(getRoleHierarchy());
           return myRoot;
      }
 }
105
Ralph

Une autre solution, vous pouvez créer une classe:

public class AuthenticationSystem {
    public static boolean isLogged() {
        final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        return null != authentication && !("anonymousUser").equals(authentication.getName());
    }
    // ...
    // Any another methods, for example, logout
}

Ensuite, dans le contrôleur:

@Controller
@RequestMapping(value = "/promotion")
public final class PromotionController {  
    @RequestMapping(value = {"", "/"}, method = RequestMethod.GET)
    public final String root() {
        if (!AuthenticationSystem.isLogged()) return "login"; // or some logic
        // some logic
        return "promotion/index";
    }
}

PS:

La solution précédente a un problème, ce qui explique Peter dans les commentaires.

@Controller
@RequestMapping(value = "/promotion")
public final class PromotionController {  
    @RequestMapping(value = {"", "/"}, method = RequestMethod.GET)
    public final String root(final Principal principal) {
        if (null == principal) return "login"; // or some logic
        // some logic
        return "promotion/index";
    }
}
14
Alexey Nikitenko

Est-ce ce que vous essayez d'atteindre?

<c:choose>
  <c:when test="${pageContext.request.userPrincipal.authenticated}">Show something</c:when>
  <c:otherwise>Show something else</c:otherwise>
</c:choose>
9
Christopher Yang

La plupart des fournisseurs d'authentification créeront un objet UserDetails en tant que principal.

Une autre méthode que j'ai trouvée - en utilisant Spring-security - consiste à vérifier si la valeur de retour de Authentication.getPrincipal() est une instance de UserDetails; la méthode retourne "anonymousUser" (String) par défaut.

boolean isUserLoggedIn(){
   return SecurityContextHolder.getContext().getAuthentication().getPrincipal() instanceof UserDetails
}
0
peter