はじめに
Spring Securityでの認証処理は、ログインフォームに入力された値をPOSTされることが前提です。
しかし、ログイン認証のパラメータをJSONにしたい場合は、デフォルトの仕様だとうまく動きません。
UsernamePasswordAuthenticationFilterを継承したフィルタを作成して行う方法などもありますが、こちらでは、手っ取り早く実装する方法を紹介したいと思います。
やり方
本来の認証処理に近づけたい場合は、フィルタを使用する方法だと思いますが、こちらで紹介する方法は、公式サイトにあった方法を踏襲しています。
ここで紹介する例は、次のURLで紹介している方法を少し改変しています。
@RestController
public class SampleLoginController {
@Autowired
private AuthenticationManager authenticationManager;
private final SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder.getContextHolderStrategy();
@PostMapping("/login")
public void login(@Valid @RequestBody LoginRequest loginRequest,
BindingResult result, HttpServletRequest request, HttpServletResponse response) {
if (result.hasErrors()) {
// 入力チェックでエラー
// ...
return;
}
// 認証情報を設定
UsernamePasswordAuthenticationToken token = UsernamePasswordAuthenticationToken.unauthenticated(
loginRequest.getUsername(), loginRequest.getPassword());
try {
// 認証
Authentication authentication = authenticationManager.authenticate(token);
// セッションの無効化
request.getSession().invalidate();
// 認証情報をセッションなどに設定
SecurityContext context = securityContextHolderStrategy.createEmptyContext();
context.setAuthentication(authentication);
securityContextHolderStrategy.setContext(context);
new HttpSessionSecurityContextRepository().saveContext(context, request, response);
// その他認証が通った後に行いたい処理がある場合はこちらに記述
// ...
} catch (AuthenticationException e) {
// 認証NGの場合
// ...
}
}
class LoginRequest {
@NotNull
private String username;
@NotNull
private String password;
// getters and setters
}
}
処理をコントローラーに直接書いちゃうという方法です。
ソースの見通しはこちらの方がわかりやすいかな?と思います。
入力チェック処理を追加したり、認証処理が通った後に現セッションを一旦無効化したり、認証が通らなかった時の処理を追加しています。
このサンプルでは戻り値はvoidですが、戻り値を設定することで、認証が通った場合、認証がNGだった場合、それぞれにおいてJSONを返したりすることもできます。
Security Configは、以下のようにコントローラーにDIするauthenticationManagerを定義します。
// デフォルトのAuthenticationManager
@Bean
public AuthenticationManager authenticationManager(final AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
そして、更に、未認証の状態で認証が必要な処理にアクセスされた場合の設定をSeurityConfigで行います。
@Bean
public SecurityFilterChain filterChain(HttpSecurity http)
throws Exception {
// 未ログインでアクセスされた場合のURLを設定
http.exceptionHandling(exception -> exception
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/unauthenticated")));
// ...
}
フォーム認証関連の設定はSecurityConfigでは一切行いません。
よって、httpSecurity#formLogin() での各種設定は行いません。
それ以外の設定は、ログインフォームでの認証の時と同じです。
最後に
こちらで紹介した方法を紹介しているページは見つからなかったのでここで紹介してみました。
本来のSpring Securityの認証処理に出来るだけ近づけたい場合は、フィルタを別途作成する方法かと思います。ネット上にもいくつか方法は紹介されています。
そちらの方法は、以下のサンプルが参考になると思います。