개발자 끄적끄적
Spring Security 본문
<Spring Security>
- 홈페이지에 인증(Authentication) 및 권한(Authorization)기능을 빠르게 부여해 인증 및 권한 보호 기능을 손쉽게 추가할 수 있는 Spring의 프레임워크 중 하나
- Spring Security is entirely based on 'servlet filter'
- ex)
Brower <-- request, response --> (Container) <-- ServletRequest, ServletResponse --> Filter --> Servlet
*Container안에 Filter와 Servlet 존재
<Security Filter Chain의 개요>
- Security Filter Chain이란 Spring Security에서 제공하는 인증, 인가를 위한 필터들의 모음
- Spring Security에서 가장 핵심이 되는 기능을 제공하며, 거의 대부분의 서비스는 'Security Filter Chain'에서 실행된다
- 기본적으로 제공하는 필터들이 있으며, 사용자는 개발의 취지와 목적에 맞게 커스텀 필터 또한 필터 체인으로 포함시켜 사용할 수 있다
[Filter Chain]
Http 요청 -> Web Application Server(Servlet Container) -> 필터1 -> 필터2... -> 필터 n -> Servlet -> 컨트롤러
<DelegatingFilterProxy>
- 사용자의 요청이 Spring MVC에 도달하기 전, 즉 Servlet Container에서 Delegating Filter Proxy가 요청을 받는다
- DelegatingFilterProxy는 Servlet Container와 Spring의 Spring Container를 연결해주는 필터이다
- Servlet 스펙에 있는 기술이기 때문에 Servlet Container에서만 생성되고 실행된다
- Spring의 Spring Container와는 다르기 때문에 Spring Bean으로 주입하거나 Spring에서 사용되는 기술을 Servlet에서 사용할 수 없습니다
- 즉, DelegatingFilterProxy는 실제 보안 처리를 하지 않고 위임만 하는 Servlet Container에서 동작하는 Servlet Filter라고 이해하면 된다
/ Servlet Container
Web Client -> DeletgatingFilterProxy -> Web resource
DeletgatingFilterProxy <-> (ApplicationContext)springSecurityFilterChain
<FilterChainProxy>
- DeletgatingFilterProxy으로부터 요청을 넘겨받은 SpringSecurityFilterChain 빈은 FilterChain의 역할을 하는 FilterChainProxy이다
<SecurityContextPersistenceFilter>
- SecurityContextRepository에서 SecurityContext을 가져오거나 생성하는 역할
*실제 SecurityContextRepository는 인터페이스이며 이를 구현한 클래스가 HttpSessionSecurityContextRepository
<SecurityContext>
- 인증 객체(Authentication)이 저장되는 객체
- 해당 객체를 SecurityContextRepository을 통해 가져오거나 생성할 수 있다
- 필터를 거쳐 인증 완료된 인증 객체를 저장하기 위한 객체
- setAuthentication() 메소드를 통해 Authentication을 설정할 수 있다
- Authentication(인증된 객체)가 저장되는 '저장소'이며, 일반적으로 ThreadLocal에 저장되며 덕분에 '전역적'으로 SecurityContext 접근 가능
<SecurityContextHolder>
- SecurityContext을 감싸는 '객체'이며 실제 SecurityContext을 위한 ThreadLocal을 가지는 객체이다
- getContext() 메소드를 통해 감싸고 있는 SecurityContext을 가져올 수 있고 clearContext()을 통해 최기화 가능
- 해당 객체가 동작하는 모드는 3가지가 있는데, 기본적으로 MODE_THREALOCAL 모드를 사용하기에 ThreadLocal을 활용해서 SecurityContext를 저장한다
- SecurityContextPersistenceFilter을 거치는 순간 SecurityContextRepository(=HttpSessionSecurityContextRepository)에서 SecurityContext을 가져오는데, 여기서 2가지 경우로 나뉜다
1. 처음 인증하거나 혹은 익명 사용자일 경우
- 세션에 저장된 것이 없을 테니 새로 SecurityContext을 생성하고 SecurityContextHolder안에 저장을 하고 다음 필터를 실행
2. 인증 이력이 있는 경우
- 이미 있는 SecurityContext을 가져와서 SecurityContextHolder에 저장한다
-> 처음 인증 시, SecurityContextPersistenceFilter는 이후의 모든 필터 동작들이 종료된 후, 다시 자신의 실행흐름으로 돌아와, 인증 완료된 Authentication 객체가 존재할 경우, 이를 SecurityContextRepository에 저장
이렇게 SecurityContext가 SecurityContextHolder에 저장된 후, 다음 필터로 진행이 이어지며, 추후 인증이 완료되면 SecurityContextHolder를 통해 Authentication 객체를 SecurityContext에 저장한다
<Spring에서 프레임워크나 라이브러리를 사용했을 때, 작동되는 구조>
1. 사용자 요청이 서버로 들어온다(Http Request)
2. Authotication Filter가 요청을 가로채고 Authotication Manager로 요청을 위임한다
3. Authotication Manager는 등록된 Authotication Provider를 조회하며 인증을 요구한다
4. Authotication Provider가 실제 데이터를 조회하여 UserDetails 결과를 돌려준다
5. 결과는 SecurityContextHolder에 저장이 되어 저장된 유저정보를 SpringController에서 사용할 수 있게 된다
<Spring Security가 작동하는 내부 구조>
1. 사용자가 자격 증명 정보를 제출하면, AbstractAuthenticationProcessingFilter가 Authentication 객체를 생성한다
2. Authentication 객체가 AuthenticationManager에게 전달된다
3. 인증에 실패하면, 로그인 된 유저정보가 저장된 SecurityContextHolder의 값이 지워지고 RememberMeService.join.Fail()이 실행된다. 그리고 AuthenticationFailureHandler가 실행된다
4. 인증에 성공하면, SessionAuthenticationStrategy가 새로운 로그인이 되었음을 알리고, Authentication이 SecurityContextHolder에 저장된다. 이후에 SecurtiyContextPersistenceFilter가 SecurityContextHttpSession에 저장하면서 로그인 세션 정보가 저장된다
그 뒤로 RememberMeServices.loginSuccess()가 실행된다. ApplicationEventPublisher가 InteractiveAuthenticationSuccessEvent를 발생시키고 AuthenticatonSuccessHandler가 실행된다
<UsernamePasswordAuthenticationFilter>
- Form Based Authentication(폼 기반 인증)을 위한 인증 필터
*폼 기반(Form Based)
- 사용자가 입력한 인증 정보인 'username'과 'password'을 통해 인증을 하는 방식으로 요청의 'Content-type'은 일반적으로 application/x-www-form-urlEncoded 이다
- 즉, 유저가 로그인 창에서 로그인 시도를 할 때 보여지는 아이디와 패스워드 데이터를 가져온 후 인증을 위한 토큰(Token)을 생성 후 인증을 다른쪽에 위임하는 역할을 필터이다
1. HttpServeltRequest 객체에서 getParamenter() 메소드를 통해 Username, Password 정보를 가져온다
2. 해당 정보를 통해 Authentication 인터페이스를 구현한 인증 전 객체 UsernamePasswordAuthenticationToken을 생성한다
3. 인증을 위해 AuthenticationManager의 authenticate 메소드를 호출하여 인증을 시도한다
<Creating a Custom Login Form(security-context.xml)>
- The line 'login-page="/Login" instructs Spring Security
- 인증되었으면, 브라우저 -> /login
- rendering the login page -> /login
- 인증이 실패되어지면 -> /login?error
- 만약 실패한 rendering하여 실패한 페이지가 보여지면 -> /login?error
*render : 템플릿을 보낼 때 사용
- view 매개변수를 갖고 있고, 때문에 '전달값에 경로를 입력해주면 오류'가 난다. 즉, 템플릿을 보내기 위한 response이다
결론 -> 템플릿 전달 + 템플릿에 전달할 객체 + 콜백함수를 통한 오류, html 확인을 원할 때
*temple(템플릿) : 자료형의 값을 넣는 것
*redirect : 경로(URL)을 보낼 때 사용
- 경로(path)와 함께 상태를 같이 보낸다
- 여기서 상태는 http 상태코드에 해당하는 양의 정수이다
- 상태를 지정하지 않는다면 상태는 기본적으로 'found'라는 뜻을 가진 '302'로 설정
만약, localhost:4000/login 이라는 페이지가 있다면 return res.redirect("/login")
- 'router -> controller -> views'로 통한다
결론 -> 경로(URL), 라우터 + 상태를 보내고 싶을 때
'웹프레임워크' 카테고리의 다른 글
JPA (0) | 2024.04.23 |
---|---|
Spring WebForm (0) | 2024.04.23 |
Spring MVC (0) | 2024.04.23 |