OAuth2.0 / JWT 기본 개념 / SecurityFilterChain (항해일지 26일차)

김형준·2022년 6월 3일
0

TIL&WIL

목록 보기
26/45

1. 개발 및 학습일지

1) OAuth2.0 페이스북, 네이버 로그인 구현

  • 🔗 구현 코드 GitHub
  • 페이스북의 경우 스프링에서 기본적으로 제공하는 oauth-client의 provider로 등록이 되어있어서 구현하는 데 얼마 걸리지 않았다.
    • 구글과 PK를 담는 키 name이 달라서 인터페이스를 만들어 사용했다.
  • 반면 네이버는 스프링이 기본으로 제공하는 provider가 아니기 때문에 application.properties에 따로 provider 등록을 해줘야 사용 가능했다.
    • 따라서 구현 과정도 살짝 다르니 나중에 코드보며 복기할 것!
  • 아마 실전 프로젝트 주차에는 프론트(리액트) 분들과 협업하며 CORS와 관련 문제를 쉽게 해결하기 위해 JWT를 사용할 것 같은데,
  • 현재 구현한 OAuth는 세션을 사용하는 스프링 시큐리티로 구현되었다. 따라서 방식이 다르다고 들었는데, 그 부분은 숙제일 것 같다. 시간 될 때 구현해볼 것!

2) JWT 학습 전 사전 지식 학습

➕세션이란?

➕세션의 문제점

➕통신이란?

➕RSA

➕JWT 로그인 과정


3) JWT 기본 개념

JWT 정의

  • 당사자간에 정보를 JSON 객체로 안전하게 전송하기 위한 컴팩트하고 독립적인 방식을 정의하는 개방형 표준(RFC- 7519)

    +RFC(Request for Comments) 문서는

    • "의견을 요청하는 문서"라는 의미로,
    • 국제 인터넷 표준화 기구(IETF; Internet Engineering Task Force)에서 관리하는 기술 표준입니다.
    • 콘텐츠에 대해 특별한 제한은 없지만 주로 프로토콜(protocol) 및 파일 형식등이 주요 주제이며
    • 승인된 문서는 유일한 일련 번호를 갖게 되며 "RFC-일련번호" 형식으로 불린다.
    • 대표적으로 웹의 기반이 되는 프로토콜인 HTTP 1.1 은 RFC-2068 에서 시작됐으며 이를 개선한 RFC-2616 도 발표되었고
    • 메일을 전송하는 프로토콜인 SMTP(Simple Mail Transfer P{rotocol) 는 RFC-821 에서 시작됐다.
    • RFC 7519 문서에 의해 정의된 것이 JWT이다.
  • 디지털 서명이 되어있어 신뢰할 수 있다. (HMAC 혹은 RSA,ECDSA를 사용하는 공개/개인 키 쌍을 사용하여 서명할 수 있음)
  • JWT를 암호화하여 당사자 간에 비밀을 제공할 수도 있지만, 서명된 토큰에 중점을 둔다.
  • 서명된 토큰은 그 안에 포함된 클레임의 무결성을 확인할 수 있다.
  • 위에 정리한 RSA 방식과 같이 공개키, 개인키를 사용하여 암호화 및 인증을 처리할 수 있다.

JWT 구조

  • Header : 토큰 유형과 사용중인 서명 알고리즘 정보로 구성된다.
  • Payload(정보):
    • 등록된 클레임(포함이 권장되는 정보 집합) -> 별로 중요하지 않음
    • 공개 소유권 주장
    • 개인 클레임: 당사자간에 정보를 공유하기 위해 생성된 지정 클레임
  • Signature : 헤더와 페이로드 그리고 Secret 키를 담고있다.

Bearer 방식이란?

쿠키의 기본적인 정책: 동일 도메인에서만 요청이 올 경우 발동된다. (동일 출처 정책)

  • 이러한 정책에 의해 아래와 같은 방식으로 http 헤더에 인증값을 넣고 움직여야한다.

  • HTTP Basic: 헤더의 Authorization (ID, PW)

    • 만약 자바스크립트단에서 다른 도메인으로 요청을 보낼 경우 헤더의 Authorization에 ID, PW를 헤더에 담아서 보낸다.
    • 이렇게 되면 Authrization이 노출될 위험이 있어 http가 아닌 https를 사용해야한다.
  • Bearer 방식: 헤더의 Authorization (Token)

    • JWT 방식에서는 헤더의 Authorization에 토큰을 넣어서 움직인다.
      • 위와 같은 방식에서 만약 토큰이 노출되더라도, ID/PW가 직접적으로 노출되는 것이 아니라 위험 부담이 적다.
      • Token은 유효시간이 있어서, 노출 되더라도 유효시간이 만료되면 사용하지 못하므로 보다 안전한 방식이라고 할 수 있다.
  • Bearer 방식을 사용하려면??

    • SecurityConfig에서
    • 세션 생성을 막아주고, (.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS))
    • formLogin도 막아주고, (formLogin().disable())
    • httpBasic도 막아준다. (httpBasic().disable())

4) Security Filter Chain에 커스터마이징 필터 추가하기

🔗 출처 -> 학습용!

  • SecurityContextPersistenceFilter - 요청(request)전에, SecurityContextRepository에서 받아온 정보를 SecurityContextHolder에 주입합니다.
  • LogoutFilter - 주체(Principal)의 로그아웃을 진행합니다. 주체는 보통 유저를 말합니다.
  • UsernamePasswordAuthenticationFilter - (로그인) 인증 과정을 진행합니다.
  • DefaultLoginPageGeneratingFilter - 사용자가 별도의 로그인 페이지를 구현하지 않은 경우, 스프링에서 기본적으로 설정한 로그인 페이지를 처리합니다.
  • BasicAuthenticationFilter - HTTP 요청의 (BASIC)인증 헤더를 처리하여 결과를 SecurityContextHolder에 저장합니다.
  • RememberMeAuthenticationFilter - SecurityContext에 인증(Authentication) 객체가 있는지 확인하고RememberMeServices를 구현한 객체의 요청이 있을 경우, Remember-Me(ex 사용자가 바로 로그인을 하기 위해서 저장 한 아이디와 패스워드)를 인증 토큰으로 컨텍스트에 주입합니다.
  • AnonymousAuthenticationFilter - SecurityContextHolder에 인증(Authentication) 객체가 있는지 확인하고, 필요한 경우 Authentication 객체를 주입합니다.
  • SessionManagementFilter - 요청이 시작된 이 후 인증된 사용자 인지 확인하고, 인증된 사용자일 경우SessionAuthenticationStrategy를 호출하여 세션 고정 보호 메커니즘을 활성화하거나 여러 동시 로그인을 확인하는 것과 같은 세션 관련 활동을 수행합니다.
  • ExceptionTranslationFilter - 필터 체인 내에서 발생(Throw)되는 모든 예외(AccessDeniedException, AuthenticationException)를 처리합니다.
    FilterSecurityInterceptor - HTTP 리소스의 보안 처리를 수행합니다.
  • Filter 클래스를 생성하여 javax.servlet.filter를 implements한다.
  • doFilter()를 오버라이드하여 메서드 바디를 구현한다.
  • 마지막에 chain.doFilter(request, response); 를 써주며 현재 필터에서 멈추지 말고, 다른 필터로 넘어가게 해준다.
  • SecurityConfig 클래스에서 http.addFilterBefore(new 필터클래스(), BasicAuthenticationFilter.class); 를 넣어주며 시큐리티 필터체인 Befor or After로 끼워 넣어준다.
  • 꼭 BasicAuthenticationFilter가 아니어도 된다 위에 그림 참고해서 적절한 필터를 선택해주면 된다.

cf) 일반 Filter 생성해서 넣어주기

@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean<MyFilter1> filter1(){
        FilterRegistrationBean<MyFilter1> bean = new FilterRegistrationBean<>(new MyFilter1());
        bean.addUrlPatterns("/*");
        bean.setOrder(0); // 낮은 번호가 필터중에서 가장 먼저 실행됨.
        return bean;
    }
}
  • @Configuration 붙이며, Bean을 등록할 클래스로 만들고
  • FilterRegistrationBean<필터클래스> 를 리턴하는 메서드를 구현
  • 메서드 바디에 FilterRegistrationBean<필터클래스> 타입의 변수를 만들고,
  • 필터가 적용될 Uri 패턴을 set해준다.
  • setOrder()를 통해서 순서를 정해줄 수도 있다.
  • 순서를 따져보면 일반 필터는 시큐리티 필터가 모두 실행된 후에 실행된다.
  • 단, 시큐리티 필터와 비교했을 경우 일반 필터는 항상 후순위로 실행된다.

2. 코멘트

  • 오늘은 하루 종일 JWT 와 관련된 강의를 들었다.
  • 기본 배경지식 부터 학습해서 좋았지만, 받아들여야하는 정보량이 정말 많았던 하루였다.
  • 기억속에서 다 날아갈까봐 노트필기해뒀다. 종종 보러와야겠다..🙃
  • 그 외에도 실제 코드를 구현해보며 얼마전 과제에서 Deprecated 됐던 WebSecurityConfigurerAdapter를 다시 살리게 되었다.
  • WebSecurityConfigurerAdapter에 담긴 AuthenticationManager를 사용하다보니 일단은 가져왔다. 내일 코드 분석해보며 다시 빼서 사용하는 코드로 수정해봐야겠다.
  • 내일 까지 해서 JWT기초 강좌를 마무리해보고 천천히 다시 구현해보자 다음주부터 실컷 써먹어야 할 것 같다..
  • 오늘도 고생했고, 내일도 힘내보자 화이팅!!
profile
BackEnd Developer

0개의 댓글