JWT 토큰으로만 인증하던 기존의 코드방식에서 Spring Security를 도입하여 코드를 리팩토링해 보는 연습을 해보았습니다. 기존에는 `JWTFilter`, `AuthArgument Resolver`를 사용하여 인증, 인가를 하고 있었습니다. 이 부분을 Refactoring 해보며 겪은 트러블 슈팅을 정리해 보았습니다.
저는 기존의 JWT 인증, 인가 방식에서 Spring Security로 리팩토링 하는 과정에서 `WebConfig` 파일에서 `AuthArgumentResolver`를 찾지못해서 오류가 발생하였습니다.
기존의 `AuthArgumentResolver`를 `JwtAuthenticationToken`으로 변경하게 되면서 기존의 커스텀 리졸버인 `AuthArgumentResolver`를 삭제하게 되어서 발생한 오류였습니다.
기존의 WebConfig 클래스
@Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {
// ArgumentResolver 등록
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new AuthUserArgumentResolver());
}
}
기존의 `WebConfig`파일에서는 `HandlerMethodArguemntResolver`를 통해서 `AuthUserArgumentResolver`클래스를 커스텀 리졸버로 추가하여 사용하였습니다. `WebConfig`클래스를 통해 등록된 커스텀 리졸버를 통해 커스텀 어노테이션 `@Auth`를 사용하여 사용자의 정보를 Controller에서 받아 가공하거나 수정하였습니다.
Spring Security를 사용하는 코드로 리팩토링 하게 되면서 리졸버를 통한 커스텀 어노테이션을 사용하지 않고, Spring Security에서 제공해주는 `@AuthenticationPrincipal` 어노테이션을 사용할 수 있게 되었습니다. 그래서 `WebConfig` 클래스를 삭제하게 되면서 해당 오류를 해결할 수 있었습니다.
@AuthenticationPrincipal 어노테이션 사용
// @AuthenticationPrincipal 사용
@PutMapping("/users")
public void changePassword(@AuthenticationPrincipal AuthUser authUser, @RequestBody UserChangePasswordRequest userChangePasswordRequest) {
userService.changePassword(authUser.getId(), userChangePasswordRequest);
}
@AuthenticationPrincipal 동작방식
간단 정리
`@AuthenticationPrincipal` 어노테이션을 사용하여 컨트롤러에서 AuthUser 객체를 받아올 수 있습니다.
`@AuthenticationPrincipal` 을 사용하면 Spring Security에서 제공하는 기본적인 인증이된 사용자 정보(AuthUser)를 추출할 수 있기 때문에 `WebConfig` 클래스의 `HandlerMethodArgumentResolver`를 통해 `AuthUserArgumentResolver`라는 커스텀 리졸버로 추가하지 않아도 사용자의 정보를 사용할 수 있게 된 것입니다.
`AuthUserArgumentResolver`는 Spring Security를 사용하지 않을때 인증된 사용자의 정보를 `@Auth` 어노테이션을 통해 컨트롤러 메서드 인자에 간단하게 주입할 수 있는 리졸버 역할을 하였습니다.
`@AuthenticationPrincipal`을 사용하면 Spring Security에서 제공하는 기본적인 사용자 정보 추출 기능(Spring Security의 `SecurityContextHolder`에서 인증된 사용자 정보를 꺼낼 수 있음)을 사용할 수 있습니다. 이 경우 `WebConfig`에서 `HandlerMethodArgumentResolver`를 별도로 등록하지 않아도 됩니다. 즉, Spring Security의 기본 기능을 활용하여 더 간편하게 사용자 정보를 주입받을 수 있습니다.
하지만 Spring Security를 사용한다 하여 `WebConfig`가 필요 없는것은 아닙니다. 서비스에서 커스텀해야 할 맞춤형 로직이 필요할 경우 `WebConfig`의 `HandlerMethdodArgumentResolver`를 사용할 수 있습니다.
예를 들어 사용자 인증 정보에서 추가적인 변환 등의 로직은 커스텀 리졸버(`AuthUserArgumentResolver`)를 정의하여 `WebConfig`에 등록하여 사용할 수 있습니다.
Spring Security 환경에서 커스텀한 사용자 객체를 주입하려면 `UserDetails`인터페이스를 구현하는 등의 방법이 있습니다.
이번 Trouble Shooting을 통해 `HandlerMethodArgumentResolver`의 동작에 대해 알 수 있었습니다. 그리고 Spring Security에서 제공해 주는 `@AuthenticationPrincipal`에 대해서도 학습할 수 있었습니다.
Reference
- Velog, "Resolver란 무엇인가?", https://velog.io/@hsjung2015/Resolver%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80
Resolver란 무엇인가?
HandlerMethodArgumentResolverArgument ResolverSpring에서 Resolver의 동작은 아래와 같은 과정으로 이루어진다.Client Request 요청Dispatcher Servlet에서 해당 요청 처리Client Request에 대
velog.io
- Tisotry, "@AuthenticationPrincipal 동작 원리와 사용 예시", https://wildeveloperetrain.tistory.com/324
@AuthenticationPrincipal 동작 원리와 사용 예시
Spring Security @AuthenticationPrincipal 동작 원리와 사용 예시 해당 포스팅은 스프링 시큐리티 환경에서 인증 후 로그인 객체를 가져오는 방법 중 '@AuthenticationPrincipal 어노테이션을 사용하는 방법과 동
wildeveloperetrain.tistory.com