시큐리티를 접하면 가장 많이 공부하게 되는 필터이고 모르고 넘어갈래야 넘어갈수가 없는 필터로 왔다 이번에는 해당 필터에 대해서 배워보자
우선 가볍게 정말 당연하지만 우리가 로그인 하는 방식을 알아보자
- 사용자는 로그인을 먼저 하는것이 아니다! 우리의 전제 조건은 항상 인증이 필요한 요청을 한 사용자의 입장에서 먼저 시작한다
- 그렇다면 시큐리티는 사용자의 인증을 확인한다.
- 우리는 인증이 되지 않은 사용자를 기준으로 공부해볼것이기 때문에 인증이 안된 사용자로 시큐리티는 인식한다.
- 그럼 우린 인증이 안된 사용자에게 로그인 창을 권유하게 되는것이다.
- 그럼 로그인창으로 사용자는 formdata에 username과 password가 담신 post형태의 데이터를 넘긴다.
- 그럼 서버는 해당 사용자를 확인하고 session 및 인증 토큰을 생성 / 저장한다
- 여기서 인증 객체를 생성하게 되는것이다. 객체의 이름은 Authentication이다.
- 인증된 객체는 Securitycontext라는곳에 저장된다.
- 이후 사용자가 또 다시 인증이 필요한 정보를 요청하게 된다면 서버는 또 다시 세션에 저장된 인증 토큰으로 접근 / 인증을 유지하게 된다.
그렇다면 http.formLogin은 어떻게 사용할까?
보이는대로 사용하게 된다. 하나씩 어떤 메소드가 어떤 역할을 하는지 알아보자
- defaultSuccessUrl = 로그인을 성공한 사용자에게 보여줄 페이지이다.
- failurUrl = 로그인을 실패한 사용자에게 보여줄 페이지이다.
- usernameParameter, passwordParameter = 이건 내가 사용한 태그의 name태그 부분의 이름을 변경해주는 것이다.
- loginProceesingUrl = 이것이 조금 헷갈릴수 있는데 여긴 폼데이터에 action 태그 즉, 폼데이터를 누르면 부르는 URL이다. 로그인하기를 누르면 **/login_proc 으로 요청이 오고 시큐리티가 로그인을 진행하여 성공과 실패를 판단한다
- successHandler, failureHandler = 성공 혹은 실패한다면 여러가지의 설정을 하고 넘겨줄수 있다
default의 경우는 그냥 별 설정없이 성공페이지로 돌리는것이고 success는 설정을 내가 하고싶은대로 할수 있다.
로그인을 진행하게 되면 UsernamePasswordAuthenticationFilter 를 반드시 타게 되는데 그 필터의 과정으로 알아보자
- 사용자는 로그인을 통해 인증을 받으려는 요청을 진행하게 될것이다.
- UsernamePasswordAuthenticationFilter에서는 그 요청을 받고 AntPathRequestMatcher에서 로그인 URL을 확인한다. 이값은 위에서 보았던 processingUrl을 통해 바꿀수 있다.
- No = chain.doFilter = 다음 필터로 넘긴다.
- Yes = Authentication에 사용자가 입력한 정보를 넣는다. Authentication객체는 인증을 받기 위해 만들어진 객체이다. 이것은 아직 인증이 되지 않은 객체이다.
- 이제 이것을 인증하는 곳으로 가게 되는데 그곳이 바로 AuthenticationManager이다. Manager는 다양한 인증 담당자 AuthenticationProvider들 중 하나에게 이일을 넘긴다. Provider는 얼마든지 커스텀 할수 있다. 그리고 여러가지 등록할수도 있다.
- No = 로그인의 정보가 서버에 있는 사용자가 아니라면 Exception을 발생한다. 그리고 Filter로 다시 넘어가며 Filter에서 실패 처리를 할것이다.
- Yes = 인증이 진행되면 인증된 객체를 다시 담는데 인증이 성공하면 UsenamePasswordAuthenticationtoken이라는 곳에 담아서 Authentication에 담는다. 해당 Token에는 사용자 개인 정보, 비밀번호, 그리고 사용자의 권한이 저장된다.
- 그럼 이 인증된 객체는 SecurityContext에 저장이 되고 이는 세션에도 저장이 되는것을 알수있다.
- 그후 filter는 성공 작업을 처리하게 될것이다.
전역으로 사용하는 Authentication
성공을 하면 정확히는 SecurityContextHolder 라는 거대한 조직에 Context형태로 저장되어 전역으로 사용할수 있게 변한다 그래서 만약 Context에 저장되어있는 사용자의 데이터를 가져오려고 할땐
SecurityContextHolder.getContext().getAuthentication() 을 사용하면 사용자의 정보들을 가져올수 있다.
Authentication
위에서 Authentication 객체라는 말을 굉장히 많이 한다. 해당 객체는 굉장히 많이 사용되지만 가장 많이 사용하고 로그인하면 떠오르는 객체로서 여기에 정리하고자 한다
우선 Authentication의 역할과 구조를 알아보자
- 사용자가 누구인지 증명하는것이다
- 사용자의 인증 정보를 저장하는 토큰의 개념
- 인증 시 id 와 password 를 담고 인증 검증을 위해 전달되어 사용된다.
- 인증 후 최종 인증 결과(User객체, 권한 정보) 를 담고 SecurityContext 에 저장되어 전역적으로 참조가 가능하다
- 이건 위에서 말한 전역에서 사용해서 가져오는 방법에 연관되어있다.
- 구조
- Principal : 사용자의 아이디 혹은 User 객체를 저장
- credentials : 사용자의 비밀번호
- authorities : 인증된 사용자의 권한 목록
- details : 인증 부가 정보
- Authenticated : 인증 여부 - true or false 로 나타낸다.
우리는 로그인을 하는 과정에 Authentication 의 객체를 설정하는데 굉장히 많은 관심이 쏠려 있다. 그럼 이제 Authentication 객체 안에서는 어떤 일이 벌어지는지 확인해보자
- 사용자가 로그인을 할때 정보를 입력하여 제공한다. 그럼 UsernamePasswordAuthenticationFilter는 이를 확인하고 Authentication 객체를 생성하여 그 안에 데이터를 집어넣는데 우선 시큐리티가 알고있는 정보 아이디와 패스워드만을 입력해 놓는다
- 이 객체는 manager에게 넘어가고 인증을 총괄하여 진행하고 인증에 성공하면 해당 객체의 내용이 바뀐다. 그후 UserDetails인 객체가 principal 로 입력되고 비밀번호는 지워진다. 그리고 사용자의 권한이 적히고 해당 Authentication객체는 인증이 되었다는 True 형태로 바뀌게 되는것이다.
- 그리고 해당 객체는 SecurityContext 에 저장되며 전역으로 사용할 수 있는것이다.
정리
로그인은 시큐리티를 다루려고 하는 사람들이 가장 먼저 접하는 Filter 공부 내용이 될 것이다. 그만큼 중요한 필터이고 커스텀또한 굉장히 많이 이루어진다. 더 많이 알게 되면 더 많은 내용을 업로드해야겠다
지금은 굉장히 어렵고 까다로워 보이지만 막상 까보면 그리고 많이 읽고 접하다보면 인증을 거치는 과정이 보일것이다. 각자의 역할을 잘 보는것이 매우 중요하다. 그리고 우리의 정보가 Authentication이라는 객체에 감싸서 시큐리티가 증명을 하는것을 잘 생각해보며 그림을 그려보자
JWT 토큰을 사용할 나는 성공시 JWT토큰을 발급하는 로직이 필요하다
'Spring > 👨💻 SpringSecurity' 카테고리의 다른 글
👨💻 JWTFilter 에서 URL의 와일드카드 사용하기(shouldNotFilter) (0) | 2023.08.04 |
---|---|
JWT (0) | 2023.07.11 |
ExceptionTranslationFilter 와 RequestCacheAwareFilter (0) | 2023.06.26 |
권한 설정 (0) | 2023.06.26 |
AnonymousAuthenticationFilter (0) | 2023.06.26 |