서론
스프링 시큐리티는 아무리 봐도 복잡하게 설계가 되어 있습니다. 각 단계를 추상화하고, 분리하다보니 중간에서 하는 일이 많아지고, 밖에서 접근하는 방법도 달라졌던 것 같습니다. Spring Security는 공부를 해보니 여전히 정말 쉽지 않은 스프링 모듈 중에 하나입니다. `Security`라는 단어에 걸맞게도 복잡하게 이루어진걸지도 모릅니다. 아무튼 공부를 하면서 제가 알아낸 정보들, 공부했던 정보들을 바탕으로 포스팅을 해보려 합니다. 또, 실전으로 연습했던 코드도 포함해서요.
이번 포스팅에서는 일단 간단하게 Security에서 저희가 짚고 넘어가야할 부분들에 대해서 적어보겠습니다.
SecurityContext
시큐리티는 시큐리티 모듈의 `SecurityContext` 안에서 인증/인가 정보가 다루어집니다. 이 Context라는 단어에서 스프링을 공부하셨던 분이라면 짐작해보실 수 있을겁니다. ServletContext, SpringContext처럼 말그대로 Security에 대한 Context를 이루고 있는 객체라는 것을 아주 잘 아실 수 있을 겁니다. 타 모듈과 마찬가지로 `SecurityContextHolder` 라는 친구 안에서 Context들이 돌아가는 거구요. 여기서 알아두어야 할 사항이 있습니다.
1. Spring Context와 Security Context는 다르다!
정말 몇번이고 강조해도 지나치지 않을 개념입니다. 저도 처음에 마찬가지로 Security Context가 무엇인지도 모를 때, 당연히 Spring Context 안에서 Security Context가 존재하는건가? 라고 헷갈렸던 적이 있었습니다. 하지만 명백히 다를 뿐만 아니라, 싱글톤을 다루고 있는 객체(`Holder`)마저 다릅니다.
위 그림에서 보듯이, 시큐리티 모듈 안에는 `filter chain`이란 친구와 `Security Context` 라는 친구가 존재하고 있습니다. 저희가 주로 다뤄야 할 친구들이 저 두 친구들이고, 그 밑에서 여러 설정을 해주면 됩니다. 그렇습니다. Spring Security가 복잡한 구조로 이루어져 있고, 알아야 할 개념이 많은 것은 사실입니다. 하지만 반대로 말했을 때 큰 그림을 그리자면, 저 두 친구를 잘 다루면 된다는 말이 됩니다.
2. 필터는 서블릿 밖에서 동작한다!
저는 필터를 처음 배울 때, 이 친구가 그저 Http 요청을 받을 때, 스프링 콘텍스트나 MVC 안에서 동작하는 친구인 줄 알았습니다. 위 그림을 보시다시피 밖에서 동작하고 있습니다. 이 개념을 전에 설명했는데도 굳이 왜 따로 적었을까요? 이유가 당연히 있습니다.
저희 개발자들은 다들 아시다시피, 어떤 앱을 개발할 때 성공의 경우만을 생각해서는 안된다는 것을 알고 계실 겁니다. 예외는 항상 저희 곁에 있고, 그 예외들도 객체로 처리해야 합니다. 예를 들면 자바에서는 `Exception` 클래스가 있죠. 그렇다면 질문이 있습니다. Spring Security에서 발생한 오류와 Spring MVC에서 발생한 오류는 같을까요?
대답은 당연히 `NO` 입니다. 저는 이 사실을 필터 쪽을 건드려보면서 알게 되었는데, 위 그림의 구조를 생각해보면 당연한 사실이었던 거죠. 말을 아무렇게나 쭉 늘어놓았는데, 글을 종합해서 말하자면 Spring Security에서 발생한 예외처리와 Spring MVC에서 발생한 예외처리는 다르다. 로 요약을 할 수 있겠습니다.
위 그림에서 나오는 `AuthenticationEntryPoint`와 `AccessDeniedHandler`가 그 핵심입니다. 이 두 에러가 인증/인가에서 예외가 발생하면 호출되는 메소드들이죠. 이 두 친구들은 이후 포스팅 때 다뤄보도록 하겠습니다.
3. 익명 인증도 인증이다!
이 부분도 개발하면서 알게된 사실입니다... Spring Security의 기본적인 인증 체계에서 다루어지는 인증 중에 `Anonymous` 권한이 있습니다. 이 친구가 개발할 때 개념을 모르고 있으면 발목을 잡는 친구 중에 하나가 될 것입니다.
예를 들어 저희가 스프링 시큐리티에서 모든 URL을 아무런 권한 없이 들어오도록 했다고 가정합시다. 그러면 Spring Security에서는 현재 들어온 사용자의 권한을 무엇이라고 지정할까요? 이게 문제입니다. "아무런 권한이 없다" 를 지정하는 인증 객체가 필요한 거죠. 아무런 권한이 없다고 하면 사실 저희는 `null` 같은 빈 객체로 처리하면 안될까? 하고 생각할 수도 있습니다(제가 그랬습니다). 이 `anonymous` 라는 권한이 "아무 권한이 없음" 권한을 담당한다는 것을 꼭 알고 있어야 합니다.
`Anonymous` 권한은 특정 필터를 통과하지 못했지만 스프링 컨텍스트를 참조할 경우에도 동작하게 됩니다. 예를 들어 보죠. 어떤 URL의 헤더에 인증 정보를 넣었는데, 헤더를 확인하는 필터를 개발했다고 합시다. 이 필터를 만들었지만, 모든 URL이 헤더를 확인하지 않을 경우가 있습니다.(예: 메인 페이지) 이 경우가 바로 저 볼드체를 한 경우가 되겠습니다. 이 경우가 바로 특정 필터를 "통과"하지 못하게 된겁니다. 자세한 예는 이후 포스팅에서 다루어보도록 하겠습니다.
요약
- Spring Context와 Security Context는 다르다!
- 필터는 서블릿 밖에서 동작한다!
- 익명 인증도 인증이다!
앞서 글에서 위 세 가지 개념을 다루어봤습니다. 제가 Spring Security 공부를 하면서 알았던 개념들이고, 이 개념들이 Security를 다루면서 꼭 짚고 넘어갈 개념들이라는 것을 알게되었습니다. 사실 위 개념들 말고도 제가 말하지 못한 개념들이 훨씬 더 많을지도 모릅니다. 일단 제가 생각나는 것 세가지를 적어보았고, 이 포스팅을 읽으시는 분들에게 시큐리티를 공부하는 데 있어서 도움이 되었으면 합니다!
'Study > Spring' 카테고리의 다른 글
(3) 스프링 시큐리티 - JWT 인증 방식 (1) | 2024.02.05 |
---|---|
(2) 스프링 시큐리티 - 스프링 시큐리티 세션 (1) | 2024.01.31 |