Spring Security authentication/authorization via REST endpoint

10,292

Solution 1

You can configure what to return on successful authentication by overriding methods in SimpleUrlAuthenticationSuccessHandler


public class CustomAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

    public CustomAuthenticationSuccessHandler() {
        super();
        setRedirectStrategy(new NoRedirectStrategy());
    }

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
            Authentication authentication) throws IOException, ServletException {

        super.onAuthenticationSuccess(request, response, authentication);
        ObjectMapper mapper = new ObjectMapper();

        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().print(mapper.writeValueAsString(objectToBereturned);
        response.getWriter().flush();
    }

    protected class NoRedirectStrategy implements RedirectStrategy {

        @Override
        public void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url)
                throws IOException {
            // any redirect if required. leave the implementation black if not needed
        }

    }
}

Additionally you can also handle the failure response:


public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
            AuthenticationException exception) throws IOException, ServletException {
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
    }
}

Solution 2

Restful calls should always return response code. In your case it should be just 200 OK. On failure 401 Unauthorized. Having different tokens is absolutely fine, you cannot use the same anyway.

I personally would prefer to handle login endpoints through Spring Security filters and not controllers as you can control the flow better.

Share:
10,292
alexanoid
Author by

alexanoid

Updated on June 17, 2022

Comments

  • alexanoid
    alexanoid almost 2 years

    In my Spring Boot application with RESTful webservices I have configured Spring Security together with Spring Social and SpringSocialConfigurer.

    Right now I have two ways of authentication/authorization - via username/password and via social networks for example like Twitter.

    In order to implement authentication/authorization via my own RESTful endpoint in my Spring MVC REST controller I have added following method:

    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public Authentication login(@RequestBody LoginUserRequest userRequest) {
        Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(userRequest.getUsername(), userRequest.getPassword()));
        boolean isAuthenticated = isAuthenticated(authentication);
        if (isAuthenticated) {
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }
        return authentication;
    }
    
    private boolean isAuthenticated(Authentication authentication) {
        return authentication != null && !(authentication instanceof AnonymousAuthenticationToken) && authentication.isAuthenticated();
    }
    

    but I'm not sure what exactly must be returned to client after successfull /login endpoint call. I think returning of full authentication object is redundant.

    What should be returned to client in case of successfull authentication ?

    Could you please tell me how to correctly implement this login method ?

    Also, in case of RESTfull login I'll have UsernamePasswordAuthenticationToken and in case of login through Twitter I'll have SocialAuthenticationToken Is it okay to have different tokens in a same application ?