Spring발행일 2024. 9. 5.원본 https://blog.naver.com/jword_/223573146652 ↗

Spring Security 구조 파악하기 [kotlin]

Spring Security 구조 파악하기 [kotlin] — #코틀린스프링 #kotlinSPRINGSECURITY #JWT #kotlinJWT #SpringLogin #SpringLogo...

#Spring#Naver Blog

#코틀린스프링 #kotlinSPRINGSECURITY #JWT #kotlinJWT #SpringLogin #SpringLogout #자바JWT

🚨📝 📖 📒✏️💡🔍

​

AI스쿨 msa기반 java 백엔드 코스 중에 공부한 내용을 작성하였습니다

\* 현재 Spring 프로젝트를 진행 중입니다. 전체적인 목차를 보시려면 여기를 눌러주세요.

이미지

로그인 기능을 만들자

어떤 서비스든 로그인 기능은 필수인데요. 이번에는 Spring Web Appliciaion에서 로그인 기능을 구현하기 위해 필요한 Spring Security에 대해 알아보겠습니다.

​

목차

  1. Spring Security Structure
  2. Spring Security Class

Spring Security Structure

Spring Security를 알아보기전에 가장 이해하는데 오래 걸렸던 부분이 바로 Spring Security의 구조입니다. 그냥 안보고 넘어가려고 했지만, 이해하지 않고 넘어갔다가 뒤에서 막혀 다시 돌아왔었습니다. 여러분들은 정석대로 전체적인 구조를 이해하시고 넘어가면 좋겠습니다.

Filter Architecuture

Spring Security는 Filter Architeucture로 구현되어있습니다. Filter Archtecture를 경험해 보신분들은 쉽게 이해를 하시겠지만, 처음 보는 저의 입장에서는 너무 어렵게 느껴졌습니다. 하지만, 전혀 어려울 필요가 없었씁니다. 왜냐하면 이름그대로 Filter를 해주는 구조이기 때문입니다.

​

그럼 무엇을 Filter해주는 걸까요? 저희가 지금 만들고 있는게 바로 Spring Web Application입니다. 그럼 서버에서 Filter할만한건 HTTP Request 밖에 없겠죠? 네, Spring Security는 HTTP 요청을 자신이 가로채 Filter를 통해 특정 로직을 실행합니다.

이미지

보통 필터라 하면 특정 기준을 두고 거르게 되는데요. 일상 생활의 예로 보면 특정 알갱이를 거르기 위해서 알갱이 보다 작은 채를 사용하는 것 처럼 말이죠. Spring Security에서의 채가 바로 url경로입니다. URL에 따라서 로직을 수행할 수 도 수행하지 않을수도 있는것이죠.

​

참고로 Spring Security는 그 이름에 걸맞게 기능으로는 인증, 인가를 주로 담당합니다. 다시말해 특정 URL로 오는 요청에는 인증을 수행하지않게 설정하거나, 모든 URL에 대한 요청에 대해 인증을 수행하도록 설정할 수 있습니다.

Spring Security Class

어떤 library를 공부할때는 주요 Class와 그에 해당하는 method를 파악하는게 기능 수행에 큰 도움이 돕니다. 그래서 우리도 Spring SEcurity의 주축을 다당하는 주요 Class에 대해 알아볼거에요.

​

최상단 필터들

DelegatingFilterProxy

이 클래스들은 Spring에 들어오는 모든 요청 처리를 제일 먼저 하는 클래스입니다..이도 역시 필터의 한 일종이며 Spring 보안 필터 체인과 연결됩니다.

​

FilterChainProxy

Spring Security의 모든 필터 체인을 관리합니다. 여기에는 다양한 보안 필터 체인이 들어있으며, 우리가 주로 알아야하는 필터 체인은 SecuirtyContextPersistenceFilter와 UsernamePasswordAuthenticaionFilter 입니다.

인증 확인 필터

위에서 다른 최상단(임의 지정) 필터를 거치고나면 본격적으로 인증을 시작해야합니다. 하지만, Spring Securiry는 Session기반으로 동작하기 때문에, 이전에 인증된 사용자 정보를 자신이 가지고 있습니다. (Db나 메모리에 저장되어있습니다.)

​

따라서 이미 인증이 된 사용자의 경우 추가적인 인증을 할 필요가 없습니다. 이를 걸러내기 위해서 SecurityContextPersistenceFilter가 사용됩니다.

​

SecurityContextPersistenceFilter

최상단 필터로 부터 온 사용자의 요청을 가장 먼저 가로챕니다. SecurityContextHolderr에 해당 요청 사용자 정보가 있는지 확인하고 있다면 인증(Authenticaion)객체를 반환합니다. 만약 없다면 빈 인증 객체를 반환하며 인증필터를 시작합니다.

​

UsernamePasswordAuthenticationFilter

가장 기본적인 인증 필터입니다. 사용자의 id및 password를 확인하여 인증 성공 여부를 결정합니다. 인증이 성공적으로 완료되면, 인증객체를 생성하여 최종적으로는 SecurityContextHolder에 저장합니다.

인증 과정 필터

이 부분은 가장 기본 형태의 인증필터인 UsernamePasswordAuthenticaionFilter의 동작 원리를 정리했습니다. 이부분이 인증의 핵심을 담당하기 때문에 제대로 이해하고 가면 좋습니다.

이미지

UsernamePasswordAuthenticaionFiter

해당 필터는 실제 많은 인터페이스를 상속받아서 사용됩니다. Spring자체적으로 구현해둔 객체로 가장 기본적인 인증을 담당하고 있습니다.

GenericFilterBean -> OncePerRequestFilter -> AbstractAuthenticationProcessingFilter -> UsernamePasswordAuthenticationFilter

다른 인증 수단으로 커스텀을 하려면, 위와 같은 인터페이스를 상속받아 사용하면 됩니다. 실제 JWT를 사용하여 인증을 하려면 커스텀 Filter객체를 만들어 사용할 수 있습니다.

​

하위 전달: 이 필터는 username & password를 기반으로 UsernamePasswordAuthenticaionToken: Autehnticaion 객체를 아래 층으로 전달합니다. (인증을 위임)

​

상위 전달: 필터는 Manager로 부터 발급된 new Token(Authenticaion 형태)을 SecurityContextHolder에 등록합니다.

​

⛓️

​

AuthenticaionManger (interface)

AuthenticaionProvider를 관리하는 인터페이스 입니다. 해당 인터페이스는 단 하나의 메서드 만을 가지고 있습니다.

fun authenticate(Authentication authentication): Authentication

하위 전달: Mangaer의 주된기능은 AuthenticaionFilter에서 전달된 Token을 분석하여 적절한 Provider에게 토큰을 넘겨주는 것입니다. 실제로 여기서 검증 로직이 구현되지 않습니다.

​

상위 전달: Provider로 부터 받은 새 Token을 Filter로 전달합니다.

​

​

⛓️

​

AuthenticaionProvider (interface)

하위 전달: 가장 핵심이 되는 객체로, 실제로 인증을 처리하는 곳입니다. 여기서는 Manger로 부터 받은 토큰을 통해 usernmae을 얻은 후 UserDetailsService에 username을 전달합니다. (username추출)

​

상위 전달: UserDetailsSevice는 UserDetails를 바탕으로 새로운 Token을 발급합니다. 이 Token을 Manager에게 전달합니다.

​

​

⛓️

​

​

UserDetailsService (interface)

단 하나의 메서드를 가지고 있습니다.

fun loadUserByUsername(String username) : UserDetails

하위 전달: Spring 환경에서는 해당 메서드를 Repository와 연동시켜서 UserEntiity를 불러옵니다. Entity를 불러왔으면 해당 정보를 바탕으로 UserDetails에 필요 정보를 넣어서 반환합니다.

return org.springframework.security.core.userdetails.User( user.username, user.password, user.isEnabled, true, // 계정 만료 여부 true, // 비밀번호 만료 여부 true, // 계정 잠김 여부 user.roles.map { SimpleGrantedAuthority(it.name) })

상위 전달: 더 많은 필드는 원하는 Spring에서 확인하시면 될 것 같습니다. 참고로 Spring에서 구현된 User : UserDetails를 그대로 보내도 되지만, 이것 역시 DTO의 한 종류이기 때문에, 필요하다면 Custom하여 전달해도 무관합니다.


이제 사용자는 인증이 완료되었습니다. 사용자는 일정 기간동안 서버로 부터 인증과정없이 허용된 resource를 요청하여 받아볼 수 있습니다.

​

여기까지는 Spring에서 시본적으로 제공하는 interface 및 class 이기 때문에 직접 구현할 필요없이 바로 사용하시면 됩니다. JWT토큰 사용사는 커스텀하게 클래스를 만들어야하는데 다음글을 참고해주세요,