Skip to content

Latest commit

 

History

History
258 lines (194 loc) · 12.3 KB

exam4.adoc

File metadata and controls

258 lines (194 loc) · 12.3 KB

Spring Boot로 만드는 OAuth2 시스템 4

간단한 OAuth2 서버 만들어 보기

이번 포스팅부터 본격적으로 OAuth2서버를 만들어 보겠다.

간단한 세팅을 시작으로 하나하나 점증적으로 확장하는 형태로 진행할 예정이다.


Client ID 계정 생성

먼저 기본적인 OAuth2 서버에서 가지는 Client ID와 Client Secret을 아래에서 설정 정보를 추가해보자.

# resources/application.properties
security.oauth2.client.client-id=foo
security.oauth2.client.client-secret=bar
# client-id : client를 식별하는 고유 정보
# client-secret : 액세스 토큰을  교환하기 위한 비공개 정보 ( 보통 암호 )

Client의 의미

OAuth2 서버를 통해 API에 접근을 허가한 클라이언트를 지칭하는 명칭이다.

클라이언트 종류로는 보통 웹, 아이폰 앱, 안드로이드 앱, PC 앱 등이 있다.

예를 들면 페이스북에서도 개발자 사이트에서 클라이언트 계정을 아래의 버튼으로 발급할 수 있다.

9RyZGAEB9zQE63TDcJSH4I1BxHQ

페이스 북에서는 스프링 시큐리티 OAuth2의 명칭과 약간 다르지만 동일한 의미를 지닌다고 생각하면 된다.

Client ID → App ID
Client Secret → App Secret
uD5KqIj1g3ieHuJhOeZNE3W1xi0

발급된 페이스북 App 계정 보통 OAuth2 인증을 지원하는 웹사이트에서는 클라이언트 계정을 발급해야 하는 관리자 페이지와 그것을 저장하는 저장소 등을 가지고 있는 경우가 많다. 클라이언트 정보 저장소로는 보통 Mysql과 같은 RDB과 NoSQL 같은 외부 저장소를 이용해서 저장해둔다. 하지만 이 같은 경우에는 가장 간단한 샘플 형태이기 때문에 직접 하드 코딩해두는 경우이다.

그래서 뒷부분에서는 확장하는 부분을 설명하면서 다른 저장소를 이용해서 클라이언트 정보를 관리하는 방법도 다룰 예정이다.


소스 작성 (실제 소스)

// DemoApplication.java
@EnableResourceServer // API 서버 인증(또는 권한 설정
@EnableAuthorizationServer // OAuth2 권한 서버
@SpringBootApplication
public class DemoApplication {
   public static void main(String[] args) {
      SpringApplication.run(DemoApplication.class, args);
   }
}

OAuth2 인증서버와 API 서버를 만들었다. ( 어노테이션 두개로 말이다!! )

놀랍지 않은가? 어노테이션 두개만 설정했을 뿐인데 설정이 완료되었다. 이것이 바로 스프링 부트의 힘이다!

사실 이번 포스팅에서 코딩은 여기 까지다. ( 테스트용 부분은 제외 )

정말 OAuth2 인증이 되는지 한 번 테스트해보자.


OAuth2의 Access Token 발급받기 테스트

테스트를 위해 추천하는 툴은 Chrome의 앱인 Postman을 추천한다. 무료인데도 불구하고 API테스트시에는 최고라고 생각된다. 물론 linux(unix) 계열 운영체제이면 curl로도 충분히 테스트 가능하다. 둘 다 설명하기 힘들기 때문에 텍스트로 설명이 가능한 curl 기준으로 설명할 예정이다. ( 윈도용 curl이 있는데 직접 설치해야 한다.)

스프링 부트에서 스프링 시큐리티 OAuth2의 기본 설정이 클라이언트의 Accees Token 발급 방법을 다섯 가지 방법으로 받을 수 있도록 활성화되어 있다. 그 다섯 가지 방식에 대해 알아 보고 테스트해보려고한다.

일단 위에서 언급한 github에서 샘플 소스를 받고 서버가 실행한 상태에서 테스트가 가능하다.


1. 권한 코드 방식 (Authorization Code flow)

보통 서버 사이트 웹에서 인증받을 때 가장 많이 쓰는 방식으로 기본적으로 지원하고 있는 방식이다.

Access Token을 받기 위한 테스트가 다른 방식에 비해 복잡하다.

(따로 인증 관련 요청 페이지 부분을 생성했다.)

먼저 바로 아래의 주소로 브라우저에서 호출한다.

yWqjPfSNnelS4nwWBT2B4xCohqc

Client의 접근을 허가 할 것인지 여부를 묻는다. 위 화면에서 Approve체크 후 하단에 Authorize버튼을 클릭하면 아래의 주소로 리다이렉트 되면서 브라우저 화면에서 curl 명령어가 보일 것이다.

$ curl -F "grant_type=authorization_code" -F "code=생성된 코드" -F "client_id=foo" -F "scope=read" -F "client_secret=bar" -F "redirect_uri=http://localhost:8080/test/authorization-code" "http://foo:bar@localhost:8080/oauth/token"

브라우저에 나타나 curl 명령어를 복사해서 실행하면 아래의 Access Token정보가 보일 것이다.

{
  "access_token":"1f94c2eb-99bb-412a-bc17-9630b1ae29dc",
  "token_type":"bearer",
  "refresh_token":"a4b037b7-f736-4bde-a073-7f88279df9bb",
  "expires_in":43199,
  "scope":"read"
}

2. 암묵적인 동의 방식 (Implicit Grant flow)

보통 클라이언트 사이드에서 OAuth2 인증하는 방식이다.

위의 주소 형태를 호출하면 redirect_uri에 입력된 주소로 리다이렉트 되면서 기본적으로 해쉬태그에서 파라메터로 Access Token을 전달해준다.


3. 자원 소유자 비밀번호 (Resource Owner Password Credentials flow)

자원 소유자 즉 사용자의 아이디(username)와 비밀번호로 Access Token 발급한다.

$ curl foo:bar@localhost:8080/oauth/token -d grant_type=password -d client_id=foo -d scope=read -d username=user -d password=test

4. 클라이언트 인증 플로우 (Client Credentials flow)

클라이언트가 직접 자신의 정보를 통해 Access Token을 발급한다.

$ curl -F "grant_type=client_credentials" -F "scope=read" "http://foo:bar@localhost:8080/oauth/token"

5. Refresh Token를 통한 Access Token 재발급

기존에 저장해둔 Refresh Token이 존재할 때 Access Token 재발급받을 필요가 있을 때 사용한다.

그리고 기존 Access Token은 만료된다.

$ curl -F "grant_type=refresh_token" -F "scope=read" -F "refresh_token=발급된 Refresh Token" "http://foo:bar@localhost:8080/oauth/token"

Access Token을 사용하여 API에 접근 테스트

위에서 여러 가지 방법으로 발급된 Access Token을 사용해서 API를 호출해보자.

$ curl -H "Authorization: Bearer 발급된 AccessToken" "http://localhost:8080/members%22[http://localhost:8080/members"
]# e.g.
$ curl -H "Authorization: Bearer 05e63e85-9614-446a-8904-aa6cc556bb1b" "http://localhost:8080/members"

json 정보가 확인되면 성공이다.


다음으로 위 소스에서 설정했던 어노테이션에 대해 한 번 살펴보자.

@EnableResourceServer

API 서버를 OAuth2 인증받게 만들도록 하며 하는 역할을 한다. 기본 옵션은 모든 API의 모든 요청에 대해 OAuth2 인증을 받도록 한다.

세부적인 설정을 위해서는 아래와 같이 ResourceServerConfigurerAdapter 클래스를 상속받아서 configure를 구현해야 한다.

// ...
@EnableResourceServer
@SpringBootApplication
public class DemoApplication extends ResourceServerConfigurerAdapter {
   @Override
   public void configure(HttpSecurity http) throws Exception {
      http.authorizeRequests()
         .antMatchers("/api/**").authenticated();
   }
// ...
}

확장을 하지 않고 기본 옵션은 모든 API는 인증이 필요한 형태로 설정된다.

OAuth2 인증을 확인하기 위하여 OAuth2 토큰 스토어 지정해야 하며, 직접 설정을 하지 않았으면 인메모리 형태로 지정된다. ( 위에서는 지정하지 않았으니 인메모리 형태로 된 상태이다. ) 위와 같이 [underline]#OAuth2 서버#와 [underline]#API 서버#가 같은 곳에서 처리되는 형태라면 같은 기본적으로 인메모리 토큰 스토어를 서로 공유하게 된다.

여기 예제에서는 스프링 부트의 기본 설정을 사용해서 모든 API를 인증받도록 할 예정이다. ( 즉 설정을 안 할 예정이다.)

참고로 스프링 부트에서 기본적으로 설정되는 Class의 위치는 아래와 같다.

org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerConfiguration


@EnableAuthorizationServer

OAuth2 인증서버를 활성화시켜주는 어노테이션이다.

OAuth2 인증을 위한 AccessToken, RefreshToken 발급과 발급된 토큰을 통한 OAuth2 인증 등 핵심기능을 활성화시켜 준다.

내부에서는 "/oauth/token", "/oauth/authorize" 등 기본적으로 OAuth2에서 사용하는 URI의 접근을 활성화 및 인증 및 내부 예외 처리 기능 등을 가진다.

세부적인 설정을 위해서는 아래와 같이 AuthorizationServerConfigurerAdapter 클래스를 상속받아서 configure를 구현해야 한다.

@EnableAuthorizationServer
@SpringBootApplication
public class DemoApplication extends AuthorizationServerConfigurerAdapter {
// ...
   @Override
   public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
// OAuth2 인증서버 자체의  보안 정보를 설정하는 부분
   }

   @Override
   public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// Client 에 대한 정보를  설정하는 부분
   }

   @Override
   public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
// OAuth2 서버가 작동하기 위한 Endpoint에 대한 정보를 설정
   }
   // ...
}

위와 같이 확장할 수 있지만 여기서는 기본적으로 Spring Boot에서 기본적으로 설정해주는 형태 그대로 사용할 예정이며 추후 필요한 형태로 확장할 예정이다.

참고로 Spring Boot에서 기본적으로 설정되는 Class의 위치는 아래와 같다.

org.springframework.boot.autoconfigure.security.oauth2.authserver.OAuth2AuthorizationServerConfiguration


Access Token 발급 테스트하는 부분이 생각보다 많이 길어졌다.

설명은 많이 했지만 사실 코드는 얼마 되지 않는다.

그리고 OAuth2 인증 자체가 복잡한 부분이 있기 때문에 테스트 조차도 복잡해진 부분이 생겼기 때문에 계속 보안할 예정이다.

OAuth2 내부에 구체적인 스펙에 관심이 있으면 국내에 출시된 OAuth2 책이 존재하니 한 번 읽어보길 권한다.

5편부터는 Spring Boot에서 지원하는 OAuth기본 설정의 부족한 부분과 확장해야 될 부분 등을 살펴보려고 한다.