はじめに
Spring Securityで、Form認証の結果をJSONで返却するための方法を調べてみました。
私が検証したバージョンは以下となります。
Version | |
---|---|
Java | 1.8 |
Spring Boot | 1.5.10.RELEASE |
サンプルコード
論よりコード。まずはサンプルコードをご覧ください。
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() // Form認証を設定
.successHandler(this) // 認証成功時のハンドラ指定
.failureHandler(this); // 認証失敗時のハンドラ指定
http.authorizeRequests().anyRequest().authenticated(); // 認証が要求されるリクエストの設定
}
// ------------------------------
// AuthenticationSuccessHandler
// ------------------------------
@Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws IOException {
MyResult result = new MyResult("認証成功"); // JSONにするオブジェクト
HttpOutputMessage outputMessage = new ServletServerHttpResponse(response);
httpMessageConverter.write(result, CONTENT_TYPE_JSON, outputMessage); // 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("認証失敗"); // JSONにするオブジェクト
HttpOutputMessage outputMessage = new ServletServerHttpResponse(response);
httpMessageConverter.write(result, CONTENT_TYPE_JSON, outputMessage); // Responseに書き込む
response.setStatus(HttpStatus.UNAUTHORIZED.value()); // 401 Unauthorized.
}
// ------------------------------
/** 認証結果 */
@lombok.Value
public static class MyResult {
private final String message;
}
}
ResponseをJSONにするには
successHandler1およびfailureHandler2で、Response内容にJSONを書き込めばよいようです。
また、認証失敗の場合はステータスが「401 Unauthorized.」になるようにしています。
Tips
ResponseをJSONにするための処理があっさり終わってしまったので、いろいろ試してみて気付いたTipsをご紹介します。
MappingJackson2HttpMessageConverter
Response内容にJSONを書き込む際は、MappingJackson2HttpMessageConverter
を使うと便利です。
自動的にヘッダにContent-Type: application/json;charset=UTF-8
もつけてくれます。
@Autowired
MappingJackson2HttpMessageConverter httpMessageConverter;
httpMessageConverter.write(result, CONTENT_TYPE_JSON, outputMessage);
ちなみに、自力でResponseに書き込む場合は以下のようになります。3
@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);
}
ハンドラのInterface実装
上記サンプルコードのように、各種ハンドラのInterfaceをWebSecurityConfigurerの実装クラスでimplementsするとコードがすっきりします。
@Configuration
public class JsonAuthConfigurer extends WebSecurityConfigurerAdapter
implements AuthenticationSuccessHandler, AuthenticationFailureHandler {
// ↑このクラスでハンドラをimplementsしているので...
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
.successHandler(this) // ←ハンドラ指定の引数は、thisでよい
.failureHandler(this); // ←ハンドラ指定の引数は、thisでよい
}
//...
}
おわりに
認証シリーズ第3弾です。過去の記事は以下になります。
Springにも大分慣れてきたような気がします。
-
org.springframework.security.web.authentication.AuthenticationFailureHandler ↩
-
org.springframework.security.web.authentication.AuthenticationSuccessHandler ↩
-
Spring boot - return user object after log in - Stack Overflowから引用 ↩