In Spring Security, I tried to find out how to return the result of Form authentication in JSON.
The version I verified is as follows.
| Version | |
|---|---|
| Java | 1.8 | 
| Spring Boot | 1.5.10.RELEASE | 
Code from theory. Please see the sample code first.
JsonAuthConfigurer.java
package example;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
@Configuration
public class JsonAuthConfigurer extends WebSecurityConfigurerAdapter
    implements AuthenticationSuccessHandler, AuthenticationFailureHandler {
  private static final MediaType CONTENT_TYPE_JSON = MediaType.APPLICATION_JSON_UTF8;
  @Autowired
  MappingJackson2HttpMessageConverter httpMessageConverter;
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.formLogin() //Set Form authentication
        .successHandler(this) //Handler specification when authentication is successful
        .failureHandler(this); //Handler specification when authentication fails
    http.authorizeRequests().anyRequest().authenticated(); //Setting of requests that require authentication
  }
  // ------------------------------
  // AuthenticationSuccessHandler
  // ------------------------------
  @Override
  public void onAuthenticationSuccess(HttpServletRequest request,
                                      HttpServletResponse response,
                                      Authentication authentication) throws IOException {
    MyResult result = new MyResult("Authentication successful"); //Object to be JSON
    HttpOutputMessage outputMessage = new ServletServerHttpResponse(response);
    httpMessageConverter.write(result, CONTENT_TYPE_JSON, outputMessage); //Write to Response
    response.setStatus(HttpStatus.OK.value()); // 200 OK.
  }
  // ------------------------------
  // AuthenticationFailureHandler
  // ------------------------------
  @Override
  public void onAuthenticationFailure(HttpServletRequest request,
                                      HttpServletResponse response,
                                      AuthenticationException exception) throws IOException {
    MyResult result = new MyResult("Authentication failure"); //Object to be JSON
    HttpOutputMessage outputMessage = new ServletServerHttpResponse(response);
    httpMessageConverter.write(result, CONTENT_TYPE_JSON, outputMessage); //Write to Response
    response.setStatus(HttpStatus.UNAUTHORIZED.value()); // 401 Unauthorized.
  }
  // ------------------------------
  /**Authentication result*/
  @lombok.Value
  public static class MyResult {
    private final String message;
  }
}
It seems that you should write JSON in the Response content with successHandler [^ fqcn-s] and failureHandler [^ fqcn-f]. Also, in case of authentication failure, the status is set to "401 Unauthorized."
Tips Since the process to make Response into JSON has been completed easily, I will introduce the tips that I noticed after trying various things.
MappingJackson2HttpMessageConverter
When writing JSON to the Response content, it is convenient to use  MappingJackson2HttpMessageConverter.
It will also automatically add  Content-Type: application / json; charset = UTF-8 to the header.
Autowired MappingJackson2HttpMessageConverter
@Autowired
MappingJackson2HttpMessageConverter httpMessageConverter;
Write JSON
httpMessageConverter.write(result, CONTENT_TYPE_JSON, outputMessage);
By the way, if you write to Response by yourself, it will be as follows. [^ quote-1]
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
  response.getWriter().write(new ObjectMapper().writeValueAsString(new UserAuthenticationResponse(authentication.getName(), 123l)));
  response.setStatus(200);
}
As shown in the sample code above, implementing the Interface of various handlers in the implementation class of WebSecurityConfigurer will make the code cleaner.
Excerpt of a clean part
@Configuration
public class JsonAuthConfigurer extends WebSecurityConfigurerAdapter
    implements AuthenticationSuccessHandler, AuthenticationFailureHandler {
    //↑ Because the handler is implemented in this class...
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.formLogin()
        .successHandler(this) //← The argument of the handler specification may be this
        .failureHandler(this); //← The argument of the handler specification may be this
  }
  //...
}
This is the third certification series. Past articles are as follows.
-Use Basic Authentication with Spring Boot -How to implement authentication process by specifying user name and password in Spring Boot
I feel like I'm getting used to Spring.
Recommended Posts