Question

We're developing a mobile app with jQuery mobile and want to authenticate the user programmatically on a spring 3.1.x backend correctly set up with spring security.

A POST request is sent to the backend (using jQuery's $.post) containing a username and password, the server then verifies if the credentials are correct and log in the user.

The server seems to correctly set the authentication in SecurityContext, however when we make a second request to the server (a $.get to a page that requires login) the security details don't seem to be remembered and an anonymous token seems to be in the context.

This is the method in the controller that handles the login (password check removed for brevity):

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

This is the other method in which we get the userdetails out of the context:

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

Spring security configuration:

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

This should work according to the spring security documentation and other online resources. Any ideas on what could be wrong?

Was it helpful?

Solution

I'm confused by your configuration. You have implemented your own login controller, but you appear to be using Spring Security's form-login. I have recently implemented ajax login with Spring Security + jquery. Instead of writing my own controller, I simply implemented my own AuthenticationSuccessHandler and AuthenticationFailureHandler to return the json responses I needed. Just extend SimpleUrlAuthenticationSuccessHandler and SimpleUrlAuthenticationFailureHandler overriding the onAuthenticationSuccess and onAuthenticationFailure methods in each class, something as simple as....

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

Then you can configure the form-login element with something like...

<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"/>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top