본문 바로가기
Spring

Spring Security OAuth2 인증서버 만들기 01

by autumnly 2019. 10. 10.

0. 서론

각기 다른 기능을 가진 독립된 서비스들을 만들어 제공하려고 할 때, 말하자면 Micro Service Architecture를 사용한 서비스 개발을 하고자 할 때, 

각 서비스에 대한 사용자들을 어떻게 관리하는 것이 좋을까 ?

각 서비스에서 관리하는 것이 아닌, 통합하여 한 곳에서 관리하려면 어떻게 해야할까?

 

이에 대한 고민에서 출발하여 찾게된 것이 OAuth 다.

 

각 서비스에 접근하고자 하는 사용자는 맨 처음 'Heowon Service (가제)' 에 접근해 회원가입을 해야한다.

Heowon Service 는 사용자의 계정, 비밀번호, 이메일주소 등 개인정보를 가지고 있게 된다.

 

회원가입을 마친 회원이 'TeamComm Service' 에 접근하려고 하면 다시 해당 서비스에 가입할 필요가 없다.

이미 통합 인증서비스인 Heowon Service 를 통해 가입했기 때문이다.

그렇다면 TeamComm Service 에서는 어떻게 Heowon Service 의 회원정보에 접근할 수 있을까?

이에 대한 해답이 바로 OAuth 이다.

 

 

 

1. OAuth 개요

OAuth 란 ?

OAuth는 인터넷 사용자들이 비밀번호를 제공하지 않고 다른 웹사이트 상의 자신들의 정보에 대해 웹사이트나 애플리케이션의 접근 권한을 부여할 수 있는 공통적인 수단으로서 사용되는, 접근 위임을 위한 개방형 표준이다.[1] 이 매커니즘은 여러 기업들에 의해 사용되는데, 이를테면 아마존,[2] 구글, 페이스북, 마이크로소프트, 트위터가 있으며 사용자들이 타사 애플리케이션이나 웹사이트의 계정에 관한 정보를 공유할 수 있게 허용한다.

 

여기서 눈여겨볼 만 한 점은, OAuth 는 접근 위임을 위한 표준이라는 것이다. 다른말로 하면 우리는 OAuth 를 통해 보호된 정보에 대한 접근을 인가받을 수 있다는 것이다.


예를 들어 TeamComm Service 에서 Hoewon Service 의 사용자 정보에 접근하고자 할 때, 그 사용자의 계정, 패스워드에 대해 알 필요가 없다. 다만 OAuth 를 통해 해당 정보에 대한 접근 권한만 인가받으면 된다.

 

이 때 접근 권한을 인가받았다는 것은 어떻게 증명할까? 바로 액세스 토큰(Access Token) 이다. 한번 토큰을 발급받으면, 토큰이 만료될 때 까지는 별도의 절차 없이 토큰만으로 정보에 접근할 수 있다.

 

이처럼 OAuth 를 사용하면, 사용자 정보 접근을 위해 토큰이 필요할 뿐, 사용자의 계정, 패스워드를 직접 주고받지 않아도 되기 때문에 안전하다. (하지만 OAuth 토큰 발급 방식 중 Resource Owner Password 방식은 계정, 패스워드를 직접 주고받는데, 이 또한 토큰을 발급받기 위한 과정으로 사용자 정보에 접근하기 위해서 토큰만이 필요하다는 사실은 변함없다. 자세한 내용은 뒤에 나올 것이다)

 

OAuth 에 대해 정리하자면 다음과 같다.

  • 리소스에 대한 접근 권한을 인가하는 표준화 된 방식이다.
  • ID/PW 직접 교환하지 않아도 되므로 신뢰할 수 없는 서비스에 개인정보를 제공할 필요가 없다. (Token 방식)
  • Token 만 있으면 다른 절차는 불필요하다.

OAuth 는 현재 2.0 이 가장 최신 버전이며, 뒤이어 설명할 내용은 모두 OAuth2.0 기준이다.

 

 

 

OAuth 용어들

OAuth 를 통한 인증/인가 절차를 살펴보기 전에, OAuth 에서 사용하는 용어에 대해 알아보자.

 

  • 자원 소유자 (Resource Owner) : 보호된 자원에 대한 접근권한을 위임해 줄 수 있는 주체. 사람일 경우 사용자.
  • 자원 서버 (Resource Server) : 보호된 자원을 가지고 있는 서버. 액세스 토큰을 가진 요청에 대해 자원을 제공해줄 수 있음.
  • 클라이언트 (Client) : 자원 소유자의 허가를 받아 보호된 자원에 접근하려는 어플리케이션.
  • 인증 서버 (Authorization Server) : 자원 소유자의 인증 및 클라이언트의 권한 획득이 끝나면, 액세스 토큰을 발급해 주는 서버. (인증 서버와 자원 서버는 분리할 수도 있고, 하나의 서버가 두 역할을 할 수도 있다.)
  • 접근 토큰(access token) : 인증 후에 클라이언트가 보호된 자원에 접근하기 위해 필요한 값.

앞서의 상황에 빗대어 보자면, 자원 소유자는 회원이다. 이 회원은 Hoewon Service 에 본인의 정보를 제공하여 가입한 상태이며, 현재 TeamComm Service 에 접근하고자 한다.

자원 서버는 Hoewon Service 다. Hoewon Service 는 현재 회원의 계정, 비밀번호, 회사정보 등을 가지고 있다.

클라이언트는 TeammComm Service 이다. 회원이 TeamComm Service 에 접근하려고 할 때, Hoewon Service 가 가지고 있는 회원 정보를 가져와 사용하고자 한다.

인증 서버는 별도의 서비스가 될 수도 있고, Hoewon Service 가 될 수도 있다. 어찌됐든 인증서버의 역할은 토큰 을 발급해주는 것이다.

 

 

OAuth 인증/인가 과정

그렇다면 OAuth 를 통한 인증/인가 과정은 어떻게 이루어질까?

간략하게 말하면 다음과 같다.

  1. 자원소유자는 클라이언트에 접근한다.
  2. 클라이언트는 자원소유자의 정보에 접근하기 위한 토큰을 얻기 위해, 인증서버에 접근한다.
  3. 인증서버는 자원소유자가 정말 그 자원에 대한 소유자가 맞는지 검증한다.
  4. 인증서버는 클라이언트가 신뢰할 수 있는 클라이언트인지 검증한다.
  5. 모든 검증이 끝나면, 인증서버는 클라이언트에게 토큰을 발급해준다.
  6. 클라이언트는 토큰을 가지고 자원서버에 접근한다.
  7. 자원서버는 토큰이 유효한지 인증서버에 확인하고, 유효하다면 자원을 제공해준다.

 

위에서 말한 3, 4 번 과정이 위 그림의 빨간네모 안 (B), (C) 과정이라고 볼 수 있다. 이 과정을 Authorization Grant 라고 하며, 토큰을 발급받기 위해 선행되어야 하는 중요한 과정이다.

 

 

OAuth 에서는 총 네 가지의 Authorization Grant 방법을 제공하는데, 다음과 같다.

  1. 인가 코드 승인 (Authorization Code)
  2. 암시적 승인 (Implicit)
  3. 자원 소유자 패스워드 승인 (Resource Owner Password)
  4. 클라이언트 인증 정보 승인 (Client Credentials)

이 중 가장 많이 쓰이는 방식이 1번 인가 코드 승인 방식이며, 우리가 OAuth 로 알고있는 대표적인 방식이다. 인가 코드 방식에 대해 이해하면 나머지 방식은 쉽게 이해할 수 있으므로, 먼저 인가 코드 방식에 대해 알아보자.

 

인가 코드 방식

전제조건 : 회원은 Heowon Service 에 가입되어 있다. TeamComm Service 는 Heowon Service 와 통신하기 위해 Client ID, Client Secret 을 발급받았다.

 

1 자원 소유자가 클라이언트에 접근하면, 클라이언트에서는 자원 소유자에 대해 아무런 정보도 가지고 있지 않은 상태다. 이 때 자원 소유자 에게 ‘Heowon Service(자원 서버) 를 통해 로그인 하기’ 와 같은 링크를 제공하여 자원 서버로부터 정보를 가져올 준비를 한다.

 

 

 

 

 

2 자원 소유자가 ‘Heowon Service(자원 서버) 를 통해 로그인 하기’ 링크를 누르면, 해당 링크를 통해 클라이언트는 인증 서버로 요청을 보내게 되고, 이 요청을 받은 인증서버는 Http 리다이렉트(302) 응답을 보낸다. 이 때 리다이렉트 링크는 인증 서버의 인증 페이지가 되고, 따라서 자원 소유자는 인증 서버의 인증 페이지를 보게 된다.

 

 

 

 

이 때 클라이언트가 인증서버로 처음 보내는 요청의 내용은 다음과 같다.

  • client_id : 사전에 인증서버로부터 발급받은 클라이언트 아이디.
  • redirect_uri : 인증서버에서의 인증이 모두 끝난 뒤 다시 돌아갈 클라이언트의 페이지.
  • state : 난수값. 추후 클라이언트-인증서버 간의 식별을 위한 값.
  • scope : 클라이언트가 원하는 자원의 범위. 추후 토큰을 발급받았을 때, 해당 정보에 대한 접근 권한만을 얻게 된다.

 

 

3 인증 서버의 인증 페이지에서, 자원 소유자는 본인의 계정/패스워드를 통해 인증을 하게된다. 이 때 클라이언트는 자원 소유자의 계정/패스워드를 볼 수가 없고, 자원 소유자가 직접 본인의 정보로 인증하므로 안전하다. 인증 서버는 자원 소유자의 인증이 정상적으로 끝나면, 앞서 클라이언트로부터 받았던 redirect_uri 로 자원 소유자를 리다이렉트 시킨다. 이 때, 리다이렉트 uri 에는 authorization code, state 값이 포함되게 된다.
authorization code 는 자원소유자의 인증이 정상적으로 완료되었다는 의미로 보내주는 값이며, state 는 클라이언트-인증서버간의 식별을 위한 값이다.

 

 

 

 

4 이제 토큰을 받기 위한 준비가 끝났다. 클라이언트는 앞서 받은 authorization code, state, 그리고 사전에 API 통신을 위해 발급받은 client id, client secret 등의 값을 가지고 인증서버에 토큰을 요청한다. 인증 서버에서는 요청정보들의 유효성을 검증한 후 토큰을 발급해주게 된다. 이 때, 앞서 클라이언트가 요청한 값의 옵션에 따라 인증서버에서 Refresh Token 을 발급해줄 수도 있는데, 이는 액세스 토큰의 유효기간이 끝났을 경우 앞서의 절차를 다시 수행할 필요 없이 토큰을 재발급받기 위한 값이다.

 

 

 

 

 

 

5 클라이언트는 토큰을 가지고 자원 서버에 자원 소유자의 정보를 요청한다. 자원 서버는 해당 토큰을 인증서버에 보내서 유효성 및 스코프를 검증한다. 인증서버에서는 토큰에 해당하는 스코프를 알려주며, 자원 서버에서는 그 스코프에 해당하는 정보를 클라이언트에게 주게 된다.

 

정리하자면 다음과 같다.

 

 

 

 

앞서 말한 네 가지의 Authorization Grant 방식 중 첫번째인 인가 코드 승인 방식에 대해 알아봤다.

 

2번 암시적 승인 방식은, 위 과정에서 Authorizaion code 를 발급해주는 대신, 바로 토큰을 발급해 주는 방식이다. 백엔드 없이 동작하는 Javascript 기반 웹 어플리케이션에서 사용하기 적합하며(Authorization code 값을 안전하게 저장하기 힘들기때문에), 토큰의 유효기간이 짧고 리프레쉬 토큰이 없다.

 

3번 자원 소유자 패스워드 승인 방식은, 앞서 언급했듯 직접 자원 소유자의 계정/패스워드를 인증서버에 요청하는 방식이다. 신뢰할 수 있는 클라이언트에만 사용해야 하며, 다른 인증방식을 사용할 수 없을 때만 사용해야 한다. OAuth 문서에서는 이 방식을 사용하여 토큰을 발급받은 후에는 자원 소유자의 계정/패스워드를 저장하지 말고 파기할 것을 권고하고 있다.

 

4번 클라이언트 인증 정보 승인 방식은 일반적으로 API 와 연동할 때 사용하는 방식으로, 사전에 API 간 연동을 위한 계정/패스워드를 발급받아 사용하는 방식이다.

 

다음 글에서는 실제 OAuth 를 사용해 인증서버를 구현하는 과정에 대해 살펴볼것이다.