쌩로그

Spring Security Form 로그인, Remember Me 본문

Spring/Spring Security

Spring Security Form 로그인, Remember Me

.쌩수. 2023. 5. 12. 01:09
반응형

나는 어차피 잘 될 사람이다.

어차피 잘 될 것이고, 지금도 잘 되고있고, 과거도 잘 되어왔기에,,,


목차

  1. 해당 포스팅에 대한 개요
       1-1. 무엇에 관련된 내용인지
       1-2. 왜 하게 되었는지
  2. 본론
       2-1. Form Login
         2-1-1. 서버와 클라이언트 요청 처리 흐름
         2-1-2. 스프링 시큐리티에서의 흐름
       2-2. LogOut
         2-2-1. 서버와 클라이언트 요청 처리 흐름
         2-2-2. 스프링 시큐리티 흐름
       2-3. Remember me
         2-3-1. 개념
         2-3-2. 흐름
         2-3-3. 결과
  3. 번외의 크롬 확장 프로그램 소개
  4. 요약

1. 해당 포스팅에 대한 개요

이번 포스팅은 오늘 내가 학습한 것에 대한 포스팅이다.

참고로 각 메서드는 나의 깃허브 소스코드에서 주석으로 표시했다.
(물론 알고있는 건 표시 안했다. 새로 배운 거 위주로 했다.)

깃허브 레포

1-1. 무엇에 관련된 내용인지

  • 결론적으로는 Spring Security에 대한 학습 내용이다.

1-2. 왜 하게 되었는지

  • Spring Security가 뭔가 계속 발목을 잡는 거 같아서 이번에 제대로 한번 학습해보려고 한다.
    코드스테이츠 부트캠프 내에서도 훌륭한 컨텐츠 제작자 덕에 알차게 봤지만, 이번에 시각적으로 보니 중복된 내용도 보이긴 했지만, 신선하게 다가왔다.

그리고 스프링 시큐리티의 학습의 전반적인 내용은 인프런에서 정수원님의 스프링 시큐리티 - Spring Boot 기반으로 개발하는 Spring Security를 기준으로 나온 내용이다.

그리고 도중에 중복된 내용이 들어오는 것이 보이니 그래도 공부를 허투루 하지는 않은 거 같아서 내심 안심이다...

2. 본론

2-1. Form Login

   Spring Security에서 제공하는 Form 태그를 이용한 인증 방식이다.

2-1-1. 서버와 클라이언트 요청 처리 흐름

   1. 사용자가 서버의 자원을 접근한다
   2. 스프링 시큐리티가 인증의 여부를 확인한다.
     2-1. 인증이 안 되있으면 리다이렉트
   3. 사용자가 username + password로 인증을 한다.
   4. 인증을 성공하면 서버가 세션을 생성한다.
   5. 세션에 다음과 같은 정보를 담는다
     5-1. 인증이 완료되면 인증 결과를 담은 토큰 혹은 Authentication 객체를 생성한다.
     5-2. 인증이 완료된 Authentication 객체SecurityContext에 담는다.
     5-3. SecurityContext를 세션에 담아서 클라이언트에게 응답한다   6. 사용자가 다시 리소스를 접근할 때,
     SpringSecurity가 사용자가 가진 세션에 인증(Authentication)의 존재여부를 판단한다.
     Authentication이 존재하면 인증된 사용자로 판단하여 리소스의 접근을 허용한다.

2-1-2. 스프링 시큐리티에서의 흐름

  1. 사용자가 인증시도를 하면 UsernamePasswordAuthenticationFilter가 받는다.
  2. AntPathRequestMather가 요청정보 Url이 로그인Url과 매칭되는지 확인한다.
       2-1. 매칭 결과가 false라면 다음 필터로 넘어간다.
  3. 매칭이 되면 인증을 시작한다.
  4. 인증이 필요한 Authentication객체를 생성해서 인증을 시작한다.
       4-1. 이 객체에는 username, password가 저장되어있다.
       ※ Authentication 타입이지만, 인증이 필요한 Authentication인 것을 주의하자❗❗
  5. 생성된 Authentication 객체AuthenticationManager로 인증처리를 위임한다.
  6. AuthenticationManagerAuthenticationProvider를 구현한 구현체인증방식에 알맞은 구현체를 찾아서 인증처리를 위임한다.
       6-1. 이 과정에서 실패하면, AuthenticationException(인증예외)를 발생시키고, 다시 1번으로 돌아간다. 그냥 다시 로그인 시도한다는 의미이다.
  7. 성공하면, 인증이 된 Authentication객체를 자신에게 인증처리를 위임했던 AuthenticationManager에게 반환한다.
  8. 이 인증이 완료된 Authentication 객체SecurityContext에 저장한다.
       8-1. 이 (인증이 완료 된) Authentication객체에는 User(UserDetails, Credential)정보User의 권한이 저장되어있다.
  9. SecurityContext세션에 저장된다.
  10. 이 후 SuccessHandler를 통해서 인증 이후의 처리를 수행한다.

2-2. LogOut

2-2-1. 서버와 클라이언트 요청 처리 흐름

  1. 사용자가 로그아웃을 요청한다.
  2. 서버는 다음과 같은 일을 한다.
       2-1. 세션무효화
       2-2. 인증이 된 Authentication과 해당 Authentication를 가지고 있는 SecurityContext삭제한다.
       2-3. 쿠키정보 삭제
  3. 로그아웃을 성공하면 로그인 페이지로 리다이렉트한다.

2-2-2. 스프링 시큐리티 흐름

  1. 로그아웃 요청시 LogoutFilter가 받는다
  2. AntPathRequestMatcher가 요청정보 Url이 로그아웃Url과 매칭되는지 확인한다.
       2-1. 만약 아니라면 다음 필터로 넘어간다.
  3. 매치가 되면, SecurityContext로 부터 인증이 된 Authetication 객체를 꺼내온다.
  4. SecurityContextLogoutHandler가 아래의 과정을 수행한다.
       4-1. 세션무효화
       4-2. 쿠키삭제
       4-3. SecurityContextHoler.clear()메서드로 SecurityContext삭제한다.
  5. 로그아웃이 완료되고, LogoutHandlerSimpleUrlLogoutSuccsessHandler호출해서 로그인 페이지로 넘어간다.

2-3. Remember me

2-3-1. 개념

  1. 세션이 만료되고 웹 브라우저가 종료된 후에도 애플리케이션이 사용자를 기억하는 기능
  2. 인증이 되었다는 건 스프링 시큐리티에서 사용자의 세션이 생성되었다는 것을 의미
       2-1. 세션에는 SecurityContext가 들어가있고, 그 안에 Authentication이 들어가있다는 의미이다.

2-3-2. 흐름

  1. RememberMeAuthenticationFilter가 사용자 요청을 받아서 아래와 같은 두 조건을 충족하면 동작한다.
       📌참고로 RememberMeAuthenticationFilter사용자의 요청을 유지한 채로 서버에 접근가능하도록 하게 하는 Filter이다.
       1. Authentication 인증 객체가 null일 경우.
         - 반대로 null이 아니라면 동작하지 않는다는 의미.
         - 그런데 Authentication객체SecutiyContext안에 담겨있는데, 왜 Authentication객체null일까?
         - 사용자의 세션이 끊기거나, 혹은 세션이 만료되어서 더 이상 세션 안에서 SecurityContext를 찾지 못할 경우. 혹은,
         - Authentication 인증 객체가 담긴 SecurityContext없는 경우이다.
       2. 사용자가 쿠키에 Remember me 토큰을 가져오는 경우.
         - 사용자가 FormLogin인증을 최초로 시도할 때, Remember me기능을 활성하여 인증을 성공한 이후에 Remember me 쿠키를 발급받아 서버로 접근하는 경우
  2. RememberMeService에서 Remember me 인증처리를 시작한다.
         - RememberMeService의 구현체
           - TokenBasedRememberMeServices
         - 메모리에서 저장한 토큰과 사용자가 요청시 담겨온 쿠키를 비교하여 인증처리를 수행       - PersistentTokenBasedRememberMeService
           - DB에 발급한 토큰과 클라이언트의 토큰을 비교하여 인증처리를 수행.
  3. Token Cookie를 추출한다.
  4. 사용자가 가진 Remember me 토큰의 이름이 Remember Me에서 설정한 이름인지 확인한다.
       - 이 때 토큰이 존재하면 그 다음 작업이 수행되고, 존재하지 않으면 다음 필터를 넘어간다.
  5. 토큰을 받고, 정상유무를 확인한다.
       - 아래 확인마다 올바르지 않으면 예외를 발생시킨다.
         - Token이 일치하는가?
         - User계정이 존재하는가
  6. 새로운 Authenication(인증 객체)을 생성한다.
  7. 이 후, AuthenticationManager에게 전달하여 인증처리가 진행된다.

2-3-3. 결과

일단은 Remember me를 체크하지 않은 로그인 결과이다.

해당 도구에서 JSESSIONID를 확인가능하다.

확인하고 나는 일단 지웠다.

그리고 다시 home쪽으로 들어가면
이처럼 로그인페이지가 나온다.

이번에는 Remember me에 체크를 한 후에 로그인을 해보자.

home으로 왔다.

이번에는 JSESSIONremember-me가 함께 저장되어있다.

그리고 역시 이번에 JSESSIONID를 쿠키에서 지워보았다.

remember-me만 저장되어있다.
그런데 아까는 쿠키에서 JSESSIONID를 지우고 home으로 갔을 땐 로그인 페이지가 나왔다.
하지만, remember-me만 있는 상황에서 home으로 가면 어떤 일이 벌어질까??

로그인 페이지를 호출한 아까와는 달리 이번엔 home에 그대로 있다.
그리고 JSESSIONID는 새로 생성되었고, remember-me의 값을 위에 사진과 비교해보면, 똑같다.

💡이처럼 Remember-me를 통해서 서버와 사용자의 인증을 유지할 수 있다!!

3. 번외의 크롬 확장 프로그램 소개

바로 위 컨텐츠를 통해서 충분히 소개된 거 같다.
참고로 삭제왼쪽 메뉴휴지통 모양 누르면 된다.

4. 요약

  1. Spring Security의 Form로그인, Login, Remember me 에 대해 알아보았다.
  2. Remember me 는 서버와 사용자의 인증을 유지하게 해준다.
  3. EditThisCookie 확장프로그램은 편하다..

여기서 잠깐!

여기서 궁금한 것이 생겼다.

`SecurityContext`는 `SecurityContextHolder`에 담기는 걸로 알고있는데, 여기선 세션에 담긴다고 하길레 궁금해서 찾아도보고, 물어도보았다.

결론은 두 곳에 모두 담긴다...
밑에 참고블로그에 나와있지만, 

"사용자가 인증처리가 완료된 후 다시 사이트를 접속했을 때 세션에 저장된 SecurityContext를 꺼내와서 SecurityContextHolder에 저장하게 된다."고 나와있다.

세션 정책에 따라서 세션을 사용할 수도 있고, 안 사용할 수도 있다고  
그리고 보통 REST API를 개발할 때는 세션을 사용하지 않도록 설정한다고 한다. 
왜냐하면 JWT를 사용하기 때문인데, 세션을 사용하면 JWT를 굳이...사용할 필요가 없기 때문이다.. 

나는 뭔가 시점이 다른가...일단 이 얘기는 나중에 포스팅하게 될 거 같다. 강의목록 보니깐 잘 나와있다.

참고 블로그
SecurityContext / SecurityContextHolder / Session
세션 정책


-끝-

728x90
Comments