2012-05-30 17 views
8

Wir entwickeln eine mobile App mit jQuery mobile und möchten den Benutzer programmatisch auf einem Spring 3.1.x Backend authentifizieren, das korrekt mit Spring Security eingerichtet wurde.Spring security: programmgesteuert anmelden

Eine POST-Anfrage wird an das Backend gesendet (mit jQuery $ .post), die einen Benutzernamen und ein Passwort enthält, der Server überprüft dann, ob die Zugangsdaten korrekt sind und meldet den Benutzer an.

Der Server scheint die Authentifizierung in SecurityContext korrekt zu setzen. Wenn wir jedoch eine zweite Anfrage an den Server stellen (ein $ .get auf eine Seite, die eine Anmeldung erfordert), werden die Sicherheitsdetails nicht gespeichert und anonymisiert Token scheint in dem Kontext zu sein.

Dies ist die Methode in der Steuerung, die das Login (Passwort-Check für Kürze entfernt) Griffe:

@RequestMapping(value = "/login", method = RequestMethod.POST, produces = "application/json") 
@ResponseBody 
public Map<String, String> login(@RequestParam String username, @RequestParam String password, HttpServletRequest request) { 
    Map<String, String> response = new HashMap<String, String>(); 

    User u = userService.findByAccountName(username); 

    if (u != null && u.hasRole("inspector")) { 
     UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password); 
     try { 
      Authentication auth = authenticationManager.authenticate(token); 
      SecurityContextHolder.getContext().setAuthentication(auth); 

      response.put("status", "true"); 
      return response; 
     } catch (BadCredentialsException ex) { 
      response.put("status", "false"); 
      response.put("error", "Bad credentials"); 
      return response; 
     } 
    } else { 
     response.put("status", "false"); 
     response.put("error", "Invalid role"); 
     return response; 
    } 
} 

Das ist die andere Methode, bei der wir die Userdetails aus dem Kontext erhalten:

@RequestMapping(value = "/project", method = RequestMethod.GET) 
@ResponseBody 
public String getProjects(HttpSession session) { 

    Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); 
    User u = userService.findByAccountName(((UserDetails) authentication.getPrincipal()).getUsername()); 
... 

Frühling Sicherheitskonfiguration:

<global-method-security pre-post-annotations="enabled"/> 
<http use-expressions="true" auto-config="true"> 

    <form-login login-processing-url="/static/j_spring_security_check" login-page="/" 
       authentication-failure-url="/?login_error=t"/> 

    ... 
    <intercept-url pattern="/api/**" access="permitAll"/> 
    ... 
    <remember-me key="biKey" token-validity-seconds="2419200"/> 
    <logout logout-url="/logout"/> 
</http> 

<authentication-manager alias="authenticationManager"> 
    <authentication-provider user-service-ref="udm"> 
     <password-encoder hash="md5"/> 
    </authentication-provider> 
</authentication-manager> 

Dies sollte nach Arbeit zur Frühjahrssicherheitsdokumentation und anderen Online-Ressourcen. Irgendwelche Ideen, was könnte falsch sein?

+0

SecurityContextHolder Standard-Richtlinie ist ThreadLocal. Jede Anfrage wird in einem neuen Thread verarbeitet (eigentlich nicht bei allen Thread-Pools, aber das spielt keine Rolle) und hat eine eigene Kopie des Context-Threading-Locals. Daher kann auf Ihre Authentifizierung, die in der Anmeldemethode festgelegt wurde, nicht in der getProjects-Methode zugegriffen werden (weil sie in einem anderen Thread ist). Sie sollten Ihre Authentifizierungsinformationen an einem bestimmten Ort speichern (z. B. http-Sitzung) und das Authentifizierungsobjekt jedes Mal wiederherstellen, wenn eine neue Anfrage beim Server eingeht (wahrscheinlich im Servlet-Filter). –

+1

Prüfen Sie http://stackoverflow.com/questions/3923296/user-granted -authorities-sind-immer-Rolle-anonym – axtavt

+0

Ich implementierte diese genaue Funktionalität mit der ausgezeichneten Antwort von axtavt verbunden. –

Antwort

11

Ich bin verwirrt durch Ihre Konfiguration. Sie haben Ihren eigenen Login-Controller implementiert, aber Sie scheinen den Formular-Login von Spring Security zu verwenden. Ich habe kürzlich Ajax Login mit Spring Security + jquery implementiert. Anstatt meinen eigenen Controller zu schreiben, habe ich einfach meinen eigenen AuthenticationSuccessHandler und AuthenticationFailureHandler implementiert, um die benötigten JSON-Antworten zurückzugeben. Nur verlängern SimpleUrlAuthenticationSuccessHandler und SimpleUrlAuthenticationFailureHandler in jeder Klasse, etwas so einfach die onAuthenticationSuccess und onAuthenticationFailure Methoden überschreiben, wie ....

public void onAuthenticationSuccess(HttpServletRequest request, 
     HttpServletResponse response, Authentication authentication) 
     throws IOException, ServletException { 
    response.getWriter().println("{\"success\": true}"); 
} 

public void onAuthenticationFailure(HttpServletRequest request, 
     HttpServletResponse response, AuthenticationException exception) 
     throws IOException, ServletException { 
    response.getWriter().println("{\"success\": false}"); 
} 

Dann können Sie das Formular-Login Element mit etwas konfigurieren wie ...

<form-login login-processing-url="/static/j_spring_security_check" login-page="/" 
      authentication-success-handler-ref="ajaxAuthenticationSuccessHandler" 
      authentication-failure-handler-ref="ajaxAuthenticationFailureHandler" 
      authentication-failure-url="/?login_error=t"/> 
+0

Dies funktionierte perfekt ... danke. – HDave

+0

Froh, dass es geholfen hat, bitte markieren Sie meine Antwort als akzeptiert – hyness

+0

Ich würde, wenn ich könnte .... – HDave