2012-05-30 1 views
8

Stiamo sviluppando un'app mobile con jQuery mobile e vogliamo autenticare l'utente in modo programmatico su un backend spring 3.1.x configurato correttamente con Spring Security.Sicurezza di primavera: accedere in modo programmatico

Una richiesta POST viene inviata al back-end (utilizzando $ .post di jQuery) contenente un nome utente e una password, il server verifica quindi se le credenziali sono corrette e accedono all'utente.

Il server sembra impostare correttamente l'autenticazione in SecurityContext, tuttavia quando facciamo una seconda richiesta al server (un $ .get a una pagina che richiede il login) i dettagli di sicurezza non sembrano essere ricordati e un anonimo il token sembra essere nel contesto.

questo è il metodo nel controller che gestisce il (controllo password rimossa per brevità) login:

@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; 
    } 
} 

Questo è l'altro metodo in cui si ottengono i UserDetails fuori del contesto:

@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()); 
... 
configurazione di sicurezza

Primavera:

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

Questo dovrebbe funzionare secondo alla documentazione sulla sicurezza di primavera e ad altre risorse online. Qualche idea su cosa potrebbe essere sbagliato?

+0

Il criterio di blocco predefinito SecurityContextHolder è ThreadLocal. Ogni richiesta viene elaborata in un nuovo thread (in realtà non tutti in caso di pool di thread, ma non importa) e hanno una propria copia del contesto che tiene threadlocal. Quindi la tua autenticazione che è stata impostata nel metodo di accesso non è accessibile nel metodo getProjects (perché è in un altro thread). È necessario salvare le informazioni di autenticazione in alcuni punti (ad esempio la sessione http) e ripristinare l'oggetto di autenticazione ogni volta che una nuova richiesta arriva al server (probabilmente nel filtro servlet) –

+1

Controllare http://stackoverflow.com/questions/3923296/user-granted -authorities-are-always-role-anonymous – axtavt

+0

Ho implementato questa esatta funzionalità usando l'eccellente risposta collegata da axtavt. –

risposta

11

Sono confuso dalla configurazione. Hai implementato il tuo controller di accesso, ma sembra che tu stia utilizzando il login form di Spring Security. Ho recentemente implementato l'accesso ajax con Spring Security + jquery. Invece di scrivere il mio controller, ho semplicemente implementato il mio AuthenticationSuccessHandler e AuthenticationFailureHandler per restituire le risposte json di cui avevo bisogno. Basta estendere SimpleUrlAuthenticationSuccessHandler e SimpleUrlAuthenticationFailureHandler sovrascrivendo i metodi onAuthenticationSuccess e onAuthenticationFailure in ogni classe, qualcosa di semplice come ....

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}"); 
} 

Quindi è possibile configurare l'elemento form-login con qualcosa di simile ...

<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

Questo ha funzionato perfettamente ... grazie. – HDave

+0

Felice di averlo aiutato, per favore segna la mia risposta come accettato – hyness

+0

Vorrei se potessi ... – HDave