Rozwijamy aplikację mobilną z jQuery mobile i chcemy programowo uwierzytelniać użytkownika na wiosennym repozytorium 3.1.x poprawnie skonfigurowanym z bezpieczeństwem sprężynowym.Bezpieczeństwo wiosenne: programowane logowanie
Żądanie POST jest wysyłane do zaplecza (za pomocą jQuery $ .post) zawierającego nazwę użytkownika i hasło, serwer następnie sprawdza, czy poświadczenia są poprawne i zalogować się do użytkownika.
Serwer wydaje się poprawnie ustawić uwierzytelnianie w SecurityContext, jednak gdy wykonamy drugie żądanie do serwera (a .get na stronę, która wymaga logowania) dane bezpieczeństwa nie wydają się być zapamiętywane i anonimowe token wydaje się być w kontekście.
Jest to metoda, w sterowniku, który obsługuje (sprawdź hasło usunięte dla zwięzłość) logowanie:
@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;
}
}
To jest inna metoda, w której otrzymujemy userdetails z kontekstu:
@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());
...
konfiguracja zabezpieczeń
Wiosna:
<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>
ten powinien działać zgodnie do wiosennej dokumentacji bezpieczeństwa i innych zasobów online. Jakieś pomysły na coś, co może być nie tak?
SecurityContextHolder domyślna polityka przechowywania to ThreadLocal. Każde żądanie przetwarzane jest w nowym wątku (właściwie nie w przypadku wszystkich pul wątków, ale to nie ma znaczenia) i ma własną kopię kontekstu zawierającego threadlocal. W związku z tym nie można uzyskać dostępu do uwierzytelniania ustawionego w metodzie logowania w metodzie getProjects (ponieważ znajduje się on w innym wątku). Powinieneś zapisać informacje uwierzytelniające w pewnym miejscu (na przykład sesję http) i przywrócić obiekt uwierzytelniania za każdym razem, gdy nowe żądanie dotrze do serwera (prawdopodobnie w filtrze serwletów) –
Sprawdź http://stackoverflow.com/questions/3923296/user-granted -Authorities-are-always-role-anonymous – axtavt
Zaimplementowałem tę dokładną funkcjonalność, korzystając z doskonałej odpowiedzi powiązanej przez axtavt. –