[Spring] Spring Security + JWT + OAuth2.0

유아 Yooa·2023년 4월 15일
0

Spring

목록 보기
1/18

Spring Security

  • 인증과 인가를 담당하는 Spring 프레임워크
  • 인증 Authentication
    - 사용자의 ID, PW가 올바른지 확인하는 일련의 작업 과정
  • 인가 Authorization
    - 사용자가 서비스를 사용할 수 있는 권한

    사용자가 올바른 인증을 하면, 서버에서 제공하는 서비스를 이용할 수 있는 권한을 관리한다라는 개념

Spring Security Structure

  • Servlet filter와 이들로 구성된 filter chain을 사용한다.
  1. Http Request : 사용자가 로그인 정보와 함께 인증 요청
  2. AuthenticationFilter가 요청을 가로챈다. 이때 가로챈 정보를 통해 UsernamePasswordAuthenticationToken 객체 생성
    - UsernamePasswordAuthenticationToken : 사용자가 입력한 데이터를 기반으로 생성, 즉 현상태는 미검증 Authentication
    3.AuthenticationManager의 구현체인ProciderManager에게 UsernamePasswordAuthenticationToken 객체를 전달
  3. AuthenticationProviderUsernamePasswordAuthenticationToken 객체를 전달
  4. 실제 DB로부터 사용자 인증 정보를 가져오는 UserDetailService에 사용자 정보를 넘겨준다.
    • 실질적인 인증 과정은 사용자가 입력한 데이터와 UserDetailServiceloadUserByUsername() 메서드가 반환하는 UserDetails객체를 비교하면서 동작한다.
    • UserDetailServiceUserDetails 구현을 어떻게 하느냐에 따라서 인증의 세부 과정이 달라진다.
  5. 넘겨받은 정보로 DB에서 찾은 사용자 정보인 UserDetails 객체를 생성
  6. AuthenticationProviderUserDetails를 넘겨받고 사용자 정보를 비교
  7. 인증이 완료되면, 사용자 정보를 담은 Authentication 객체를 반환
  8. 최초의 AuthenticationFilterAuthentication 객체를 반환
  9. Authentication 객체를 SecurityContext에 저장

OAuth 2.0 (OpenID Authentication)

  • 타사의 사이트에 대한 접근 권한을 얻고 그 권한을 이용하여 개발할 수 있도록 도와주는 프레임워크
  • Google, Kakao, Naver 등 사이트에서 로그인을 하면 직접 구현한 사이트에서도 로그인 인증을 받을 수 있는 구조
  • 로그인을 했다고 해서, 개발한 웹 사이트에 구글 ID와 PW를 그대로 전달해주면 안되므로, Access Token을 발급 받고 그 토큰을 기반으로 원하는 기능을 구현해야 한다.

Access Token

  • 로그인을 하지 않고 인증을 할 수 있도록 해주는 인증 토큰의 개념이다.
  • Access Token을 통해 해당 정보 권한을 받아와 그 정보를 토대로 작업을 할 수 있게 된다.
  • Access Token을 발급 받기 위한 일련의 과정들을 인터페이스로 정의해둔 것이 OAuth

OAuth2

  • Resource Owner : 개인 정보의 소유자 (e.g. 회원)
  • Client : 제 3의 서비스로부터 인증을 받고자 하는 서버 (e.g. 개발 서비스)
  • Resource Server : 개인 정보를 저장하고 있는 서버 (e.g. Google)
  • Client ID : Resource Server에서 발급해주는 ID
    - 개발 DOCS 참고하여 등록/발급받을 수 있다.
  • Client Secret : Resource Server에서 발급해주는 PW
    - 개발 DOCS 참고하여 등록/발급받을 수 있다.
  • Authorized Redirect URI : Client에서 등록하는 URI. 만약 이 URI로부터 인증을 요구하는 것이 아니라면, Resource Server는 해당 요청을 무시한다.

동작 설명

ClientResource Server에 등록이 완료되었다면 Access Token을 발급받을 수 있다.

//예시 링크
https://accounts.google.com/
?client_id=123
&scope=profile,email
&redirect_uri=http://localhost

사용자가 정상적으로 로그인 했다면, Google은 이전에 등록되었던 Client ID인 서버의 Redirect URI가 동일한지 확인한다.

일치한다면 유저에게 scope 기능을 넘겨줄 것인지에 대한 승인 여부를 물어보고 동의한다면 이에 해당하는 authorization_code라는 임시 PW를 발급한다.

이후 http://localhost/?authorization_code=2 로 리다이렉트 되며, 개발 서비스의 서버는 이 authorization_code를 가지고 Google에게 Access Token을 요청한다. 사용자의 인증이 필요할 때마다 Access Token을 이용하여 접근한다.


서버 기반 인증 방식

  • 서버 측에 사용자 정보를 저장하는 것
  • Spring Security에서 별도 설정이 없으면 Session을 이용해 처리한다.

세션 인증 방식

  • 로그인을 통해 사용자를 확인하고 사용자 정보를 세션에 저장하여 Session ID를 사용자에게 응답한다.
  • 클라이언트는 요청마다 HeaderSession ID가 담긴 Cookie를 넣어 통신하고, 서버에서는 Cookie를 검증하여 데이터를 응답한다.
  • 만약 마이크로 서비스 개발을 진행하거나 서버를 확장하게 된다면, 모든 서버에게 Session 정보를 공유해야 하므로 이를 위한 별도의 중앙 세션 관리 서버를 두곤 한다.

JWT 기반 인증 방식 (Json Web Token)

  • Claim 기반 방식을 사용한다.
    - Claim : 사용자에 대한 속성 값
  • 의미있는 토큰(사용자 상태 포함)으로 구성되어 있기 때문에, Auth Server에 검증 요청을 보내야만 했던 과정을 생략하고 각 서버에서 수행할 수 있게 되어 비용 절감 및 Stateless 아키텍처를 구성할 수 있다.

동작 과정

  • 클라이언트는 Auth Server에 로그인을 한다.
  • Auth Server에서 인증을 완료한 사용자는 JWT 토큰을 전달 받는다.
  • 클라이언트는 특정 어플리케이션 서버에 리소스를 요청할 때, 전달받은 JWT 토큰을 Authorization Header에 넣어 전달한다.
  • 어플리케이션 서버는 전달 받은 JWT 토큰의 유효성을 직접 검사하여 사용자 인증을 할 수 있다.

특징

  • 확장성에 큰 강점을 가진다.
    - Session을 사용하는 경우, 서버를 확장할 때마다 각 서버에 세션 정보를 저장해야 한다. 특정 서버에서 로그인 인증을 받을 때 다른 서버는 로그인했는지 알 수 없다.
    - JWT는 서버의 수와는 상관없이 토큰을 인증하는 방식을 알고 있으면 인증 과정에 문제가 없다.
  • 웹과 앱 간의 Cookie 세션 처리에도 유용하다. 브라우저와 앱서의 쿠키 처리 방법은 각기 다를 수 있기 때문에 JWT를 이용하는 것이 다양한 디바이스 차원에서 좋다.
  • 사용자 인증 정보가 필요한 요청을 보낼 때 헤더에 JWT 토큰값을 넣어 보내기 떄문에 데이터가 증가해 네트워크 부하가 늘어날 수 있다.
  • 토큰 자체에 사용자 정보를 담고 있기에 JWT가 만료되기 전에 탈취당할 수 있다.
  • 한 번 만들어 클라이언트에게 전달하면 제어가 불가능하기에 만료 시간을 필수적으로 넣어주어야 한다.
    - 짧은 만료 기간을 갖는 JWT 형식의 Access Token과 긴 만료 기간을 갖는 JWT 형식의 Refresh Token 두 가지를 사용한다.
    • Refresh Token을 DB에 저장하고 새로운 Access Token을 발급받기 위해 거쳐야 하는 추가적인 과정이 생기게 된다.

Access Token과 Refresh Token

  • Access Token
    - 리소스(사용자의 정보)에 직접 접근할 수 있도록 하는 정보만을 가지고 있다.

    • 짧은 만료 기간을 가지며, 주로 Session에 담아 관리한다.
  • Refresh Token
    - 새로운 Access Token을 발급 받기 위한 정보를 담고 있다.

    • 클라이언트가 Access Token이 없거나 만료된 상태라면, Refresh Token을 통해 Auth Server에 요청하여 새로운 Access Token을 발급받을 수 있다.
    • 외부에 노출되지 않게 하기 위해 보통은 DB에 저장하곤 한다.
  • 마이크로 서비스이거나 서버 간의 통신이 잦은 경우, Access Token을 자주 주고받을 수 밖에 없다.

  • 각 서버는 API 호출 요청에 대해서 전달 받은 Access Token이 유효한 지를 확인해야 한다. 이는 서버에서 클라이언트의 상태(= Access Token 유효성)를 관리하게끔 한다.

  • API를 호출할 때마다 Access Token이 유효한지 매번 DB에서 조회하고 새로 갱신 시 업데이트 작업을 해주어야 한다.

    클라이언트 상태를 관리 및 공유할 추가적인 저장 공간과 매 요청마다 Access Token의 검증 및 업데이트를 위한 DB 호출이 발생하는 구조

  • 마이크로 서비스 개발처럼 서버의 수가 많은 경우, 각각의 서버가 Access Token의 유효성 및 권한 확인을 Auth Server에 요청하기 때문에 병목 현상 등이 발생해 서버 부하로 이어질 수 있다.


참고

profile
기록이 주는 즐거움

0개의 댓글