wake-up-neo.net

Spring MVC - Prüfen, ob der Benutzer bereits über Spring Security angemeldet ist?

Ich habe eine Spring-MVC-Anwendung. Sie verwendet eine eigene benutzerdefinierte Anmeldeseite . Bei erfolgreicher Anmeldung wird ein 'LOGGED_IN_USER' Objekt in die HTTPSession gestellt.

Ich möchte nur authentifizierten Benutzern den Zugriff auf URLs erlauben. Ich weiß, dass ich dies mit einem Webfilter erreichen kann. Aber diesen Teil möchte ich mit Spring Security machen (mein Check bleibt derselbe - suchen Sie in HTTPSession nach dem 'LOGGED_IN_USER'-Objekt, falls Sie angemeldet sind).

Meine Einschränkung ist, dass ich das Login-Verhalten derzeit nicht ändern kann - Spring Security wird noch nicht verwendet.

Welchen Aspekt von Spring Security kann ich verwenden, um diesen Teil alleine zu erreichen? Überprüfen Sie, ob die Anforderung authentifiziert ist (vom angemeldeten Benutzer).  

39
Jasper

Es gibt mindestens 4 verschiedene Möglichkeiten:

federsicherheit XML-Konfiguration

dies ist der einfachste Weg

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

Per @Secured Annotation

erfordert <global-method-security secured-annotations="enabled" />

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

Per @PreAuthorize-Anmerkung

erfordert <global-method-security pre-post-annotations="enabled" />

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

Programmatisch

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

Benutzerdefinierter Ausdruck

Wenn die integrierten Ausdrücke nicht ausreichen, können Sie sie erweitern. Wie Sie die SpEL-Ausdrücke für die Methodenanmerkungen erweitern, wird hier zum Beispiel erläutert:

Für den Interceptor <security:intercept-url ... access="myCustomAuthenticatedExpression" /> ist jedoch ein etwas anderer Ansatz möglich, der sich nicht mit dem Problem der privaten Klasse befassen muss. - Ich habe es nur für Spring Security 3.0 gemacht, aber ich hoffe, dass es auch für 3.1 funktioniert.

1.) Sie müssen eine neue Klasse erstellen, die sich von WebSecurityExpressionRoot erstreckt (Präfix-Web ist der wichtige Teil!).

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.) Sie müssen die Variable DefaultWebSecurityExpressionRootHandler erweitern, um einen Handler zu haben, der Ihren benutzerdefinierten Ausdruckswurzel bereitstellt

 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.) Dann müssen Sie Ihren Handler bei den Wählern registrieren

<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

Seit Spring Security 3.1 ist es etwas einfacher, einen benutzerdefinierten Ausdruck zu implementieren. Man muss nicht länger WebSecurityExpressionHandler sublcass machen und createEvaluationContext überschreiben. Stattdessen eine Unterklasse AbstractSecurityExpressionHandler<FilterInvocation> oder ihre Unterklasse DefaultWebSecurityExpressionHandler und überschreiben 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

Eine andere Lösung können Sie Klassen erstellen:

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
}

Dann im Controller:

@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:

Vorherige Lösung hat ein Problem, das Peter in Kommentaren erklärt.

@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

Ist es das, was Sie erreichen wollen?

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

Viele Authentifizierungsanbieter erstellen ein UserDetails-Objekt als Prinzipal.

Eine andere Methode, die ich gefunden habe - mithilfe von Spring-Security - besteht darin, zu prüfen, ob der Rückgabewert von Authentication.getPrincipal() eine Instanz von UserDetails ist. Die Methode gibt standardmäßig "anonymousUser" (String) zurück.

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