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?
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) –
Controllare http://stackoverflow.com/questions/3923296/user-granted -authorities-are-always-role-anonymous – axtavt
Ho implementato questa esatta funzionalità usando l'eccellente risposta collegata da axtavt. –