스프링 시큐리티가 꼭 필요할까?

Alex·2025년 1월 18일
0

CS를 공부하자

목록 보기
16/74

이 글을 통해서 스프링 시큐리티에 대한 생각을 좀 정리해보고자 한다.

우선, 이 글을 쓰게 된건

Spring Security 그렇게 쓰지 마세요!
라는 글을 봤기 때문이다.

골자는 스프링 시큐리티를 정말 필요해서 쓰는 게 맞냐는것이다.
나는 스프링 시큐리티를 쓰지 않고 스프링 시큐리티와 비슷한 방식으로 로그인 기능을 구현했다.
사실 그래서 그런지 꼭 스프링 시큐리티가 필요한가? 하는 생각이 들었다.

이번에 스프링 시큐리티로 마이그레이션을 하면서 생각보다 많은 변경이 있었고, 로그인쪽 비즈니스 로직을 아예 싹다 옮기느라 테스트를 고치는 게 많은 시간이 들어갔다...

아직 보안 기능들을 적용하지 않아서 득보단 실이 많은 상황...ㅎㅎ..

우선, 스프링 시큐리티는 쓰는 것이 좋다.

나는 그렇게 생각한다.
스프링 시큐리티를 통해서 메서드단위로 권한을 조절할 수 있고,
스프링 시큐리티에서 제공하는 여러 보안 기능들을 활용할 수 있기 때문이다.
(사실 보안 기능들을 더 공부를 해야 한다 아직 적용해보지 않았다)

이 글이 나는 맞다고 생각한다. 이전의 구조처럼 JWT 로그인 방식과 비밀번호 암호화정도만 구현해놓고, 스프링 시큐리티 기능이 필요하면 이를 활용하면 된다.

그렇다면, 뭐가 문제라는거야?

스프링 시큐리티에 의해 비즈니스 로직이 숨겨진다

스프링 시큐리티와 JWT로그인을 구현할 때 나는 별도로 login API url을 설정한 뒤, 비즈니스 로직에 맞춰서 로그인 기능을 구현했다.

다만, 불편한점은 이 로그인 url이 스프링 시큐리티에 의해서 숨겨진다는 것이다. 컨트롤러에 로그인 API가 있는 것도 아니고, 스웨거에 로그인 API가 뜨는 것도 아니다.

위에서 언급한 참고 글에선 이러한 경우를 애플리케이션의 유스 케이스가 프레임워크에 의해서 결정되는 사례라고 말한다.

API URL이 드러나지 않으면 클라이언트와 소통할 때 불편하다. 어떠한 헤더나 바디가 별도로 필요하다면 이걸 맞춰가는 것도 필요하다. 큰 불편함?까지는 아니더라도, 문서화가 안되니 불편한 건 사실이다.

스웨거를 통해서 문서화용도로만 API가 나오도록 했지만
이건 응답을 반환하지 않는다.

처음 스웨거를 봤을 때 로그인 기능에 문제가 있는건가? 하는 오해를 할 수 있다고 본다.

스프링 시큐리티를 제대로 이해하지 못하고 사용한다.

Spring Security Filter 를 이용해 로그인 인증을 구현하는데 UserDetailsService, UserDetails 개념이 필수적일까?

아니라고 한다.

나도 실제로 이렇게 만들어서 사용하고 있었다.

UserDetailsService 는 AbstractUserDetailsAuthenticationProvider의 구현체인 DaoAuthenticationProvider 와 협력하는 데 쓰는 객체다.

AbstractUserDetailsAuthenticationProvider가 UserDetailsService를 통해서 유저정보를 가져온다.

직접 AuthenticationProvider 의 구현체를 만들었다면 굳이 UserDetailsService 의 구현체를 이용해 사용자 정보를 읽어올 필요가 전혀 없다.

이미 프로젝트에 구현되어 있을 UserService 를 이용해 사용자 정보를 읽어오면 된다.

UserDetailsService 의 구현체를 만들게 되면 loadUserByUsername 를 오버라이딩 하게되고 이 메소드는 UserDetails 를 반환해야한다.

도메인영역인 User가 UserDetails 를 구현하도록 만들어야 하는데,
도메인까지 프레임워크인 Spring Security 에 의존하는 구조가 되버린다.

UserDetails 인터페이스는 isAccountNonExpired, isAccountNonLocked, isCredentialsNonExpired 등 다양한 추상메소드를 포함하고 있어 불필욯나 메서드들도 오버라이드 해야 한다.

지금은 AuthenticationProvider를 구현하고 있지 않고있고, UserDetails를 도메인과 별도인 응답 DTO로 만들어서 쓰고 있다.

코드를 리팩토링할 필요까진 안 느껴지는데, 나중에 OAuth2를 사용하면서 변경이 필요하면 바꿀 계획이다.

추가 공부

스택오버플로우의 답변인데,

이 사람은

  • DB에서 정보를 조회해야 할 땐 UserDetailsService를 사용하고
  • 그렇지 않으면 AuthenticationProvider를 쓴다고 한다.

스프링 시큐리티 공식문서에서는, custom authentication process가 필요할 땐 AuthenticationProvider를 구현하는 게 더 자연스럽다고 언급하고 있다.

시스템이 좀더 복잡해지면(그룹웨어, 인사관리, 회계, 영업등 다양한 시스템에서 정보를 취합해야 할 때 / 소셜 로그인을 여러개로 구현할 때)

정보를 가져오는 부분과 인증을 하는부분의 책임을 나눌 때 두가지를 같이 구현하는 거라고 생각하면 될 거 같다.

OncePerRequestFilter는 Spring Web 이 제공하는 Filter다.

지금 구현한 JWT 필터는 OncePerRequestFilter를 구현해서 사용중이다. 다만, 이건 스프링 시큐리티의 필터가 아니라고 한다. 스프링 시큐리티를 통해서 동작하는 필터를 만들려면, AbstractAuthenticationProcessingFilter 를 구현해야 한다.

AbstractAuthenticationProcessingFilter가 비즈니스 로직을 구현할 때 좀더 도움이 된다.

근데 어떤 측면에서 도움이 되는지 찾아보니 참고자료이 글에선 AbstractAuthenticationProcessingFilter를 쓰면

생성자에 동작해야 할 url 목록을 지정할 수 있다고 한다.
나는 OncePerRequestFilter에서 shouldNotFilter를 쓰긴 했는데
아직 당장은 고쳐야할 필요를 크게 못느껴서 나중에 리팩토링을 해야겠다.

결론은

  • 스프링 시큐리티에 의해서 로그인 API가 감춰지는 건 비즈니스 로직이 라이브러이에 종속되는 현상이고
  • 스프링 시큐리티 라이브러리 간의 자연스러운 협력이 무엇일지 고민이 필요하다는 것이다.
profile
답을 찾기 위해서 노력하는 사람

0개의 댓글