반응형
  • 배경지식 소개
  • 스프링 부트 시큐리티 + OAuth2 설계하기
  • 스프링 부트 시큐리티 + OAuth2 의존성 설정하기
  • 스프링 부트 시큐리티 + OAuth2 구현하기
  • 스프링 부트 2.0 기반의 OAuth2 설정하기

배경지식 소개

스프링 부트 시큐리티에서 가장 중요한 개념은 인증(Authentication)과 권한 부여(Authorization)입니다.

인증은 사용자(클라이언트)가 애플리케이션의 특정 동작에 관하여 허락된 사용자인지 확인하는 절차를 말합니다.

보통 웹사이트 로그인을 인증이라 생각하면 됩니다.

권한 부여는 데이터나 프로그램 등의 특정 자원이나 서비스에 접근할 수 있는 권한을 허용하는 겁니다.

 

인증 방식은 다양합니다. 전통적인 인증방식으로 사용자명과 비밀번호로 인증하는 '크리덴셜 기반 인증 방식' OTP와 같이 추가적인 인증 방식을 도입해 한번에 2가지 방법으로 인증하는 '이중 인증 방식' 소셜 미디어를 사용해 편리하게 인증하는 'OAuth2 인증 방식' 

 

OAuth2

OAuth 토큰을 사용한 범용적인 방법의 인증을 제공하는 표준 인증 프로토콜입니다.

OAuth2에서 제공하는 승인 타입은 총 4가지입니다.

 

권한 부여 코드 승인 타입

 - 리소스 접근을 위한 사용자명과 비밀번호, 권한 서버에 요청해서 받은 권한 코드를 함께 활용하여 리소스에 대한 액  세스 토큰을 받으면 이를 인증에 이용하는 방식

 

암시적 승인 타입

- 권한 부여 코드 승인 타입과 다르게 권한 코드 교환 단계 없이 액세스 토큰을 즉시 반환받아 이를 인증에 이용하는 방식

 

리소스 소유자 암호 자격 증명 승인 타입

- 클라이언트 암호를 사용하여 액세스 토큰에 대한 사용자의 자격 증명을 교환하는 방식

 

클라이언트 자격 증명 승인 타입

- 클라이언트가 컨텍스트 외부에서 액세스 토큰을 얻어 특정 리소스에 접근을 요청할 때 사용하는 방식

 

여기서는 권한 부여 코드 승인 타입을 눈여겨보겠습니다. 페이스북, 구글, 카카오 등 소셜 미디어들이 웹 서버 형태의 클라이언트를 지원하는 데 이 방식을 사용하기 때문입니다.

 

권한 부여 코드 승인 타입 시퀀스 다이어그램

권한 부여 코드 승인 타입 시퀀스 다이어그램

 

스프링 부트 시큐리티 + OAuth2 설계하기

1. 사용자가 애플리케이션에 접속하면 해당 사용자에 대한 이전 로그인 정보(세션)의 유무를 체크합니다.

2. 세션이 있으면 그대로 세션을 사용하고, 없으면 OAuth2 인증 과정을 거치게 됩니다.

3. 이메일을 키값으로 사용하여 이미 가입된 사용자인지 체크합니다. 이미 가입된 사용자라면 등록된 정보를 반환하여 요청한 URL로 의 접근을 허용하고, 아니라면 새롭게 User 정보를 저장하는 과정을 진행합니다.

4. 각 소셜 미디어에서 제공하는 User 정보가 다르기 때문에 소셜 미디어에 따라 User 객체를 생성한 후 DB에 저장합니다.

 

스프링 부트 시큐리티 + OAuth2 의존성 설정하기

기존 spring 1.5버전에는 spring-security-oauth2만 설정해주어도 OAuth2 관련 모든 설정이 끝났지만 2.0부터는 설정이 세분화되었습니다. 기본적인 OAuth2 인증 관련 객체들이 시큐리티로 이전되었습니다.

 

스프링 부트 시큐리티 + OAuth2 구현하기

소셜 미디어중에서 카카오 OAuth2 로그인을 구현해보겠습니다.

먼저 카카오의 개발자센터에서 '클라이언트 ID'와 Secret(클라이언트 시크릿 키값, 클라이언트 보안 비밀)을 발급받아보겠습니다.

 

Kakao Developers 접속합니다.

- developers.kakao.com/console/app

 

1. 애플리케이션 추가하기

 

2. 플랫폼 선택 후 Web 플랫폼 등록

 

3. Redirect URI 등록하러 가기

  - 인증이 완료된 후 redirect 될 URI를 작성해줍니다. 

이로써 클라이언트 ID 발급은 끝났습니다.

 

SNS 프로퍼티 설정 및 바인딩

application.yml 파일에 아래와 같이 작성합니다.

구글, 페이스북에 대한 기본 정보는 스프링 부트 시큐리티 OAuth2 API에서 제공합니다.

그러므로 SNS 개발자센터에서 받은 ID와 Secret만 프로퍼티로 등록해주면 됩니다.

 

국내에서만 사용되는 소셜은 OAuth2 API에서 제공하는 방법과 동일하게 소셜 정보를 담은 객체를 생성합니다.

 

스프링 부트 시큐리티에서 제공되는 CommonOAuth2Provider.java 방법과 동일하게

CustomOAuth2Porvider.java에 KAKAO OAuth2 로그인 정보를 빌더로 생성

SecurityConfig.java

ouath2Login()만 추가로 설정하면 기본적으로 제공되는 구글과 페이스북에 대한 OAuth2 인증 방식이 적용됩니다.

추가적으로 @EnableWebSecurity 어노테이션은 웹에서 시큐리티 기능을 사용하겠다는 어노테이션입니다.

자동 설정 그대로 사용할 수도 있지만 요청, 권한, 기타 설정에 대해서는 필수적으로 최적화한 설정이 들어가야 합니다.

최적화 설정을 위해 WebSecurityConfigurerAdapter를 상속받고 configure(HttpSecurity http) 메서드를 오버라이드하여 원하는 형식의 시큐리티 설정을 합니다.

다음은 오버라이드한 configure() 메서드의 설정 프로퍼티에 대한 설명입니다. 더 많은 설정 항목이 있지만 해당하는 프로퍼티만 나열하겠습니다.

authorizeRequests() - 인증 매커니즘을 요청한 HttpServletRequest 기반으로 설정합니다.

- antMatchers() - 요청 패턴을 리스트 형식으로 설정합니다.

- permitAll() - 설정한 리퀘스트 패턴을 누구나 접근할 수 있도록 허용합니다.

- anyRequest() - 설정한 요청 이외에 리퀘스트 요청을 표현합니다.

- authenticated() - 해당 요청은 인증된 사용자만 할 수 있습니다.

 

headers() - 응답에 해당하는 header를 설정합니다. 설정하지 않으면 디폴트값으로 설정됩니다.

- frameOptions().disable() - XFrameOptionsHeaderWriter의 최적화 설정을 허용하지 않습니다.

 

authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login")) - 인증의 진입 지점입니다. 인증되지 않은 사용자가 허용되지 않은 경로로 리퀘스트를 요청할 경우 '/login'으로 이동됩니다.

 

formLogin().successForwardUrl("/board/list") - 로그인에 성공하면 설정된 경로로 포워딩됩니다.

 

logout() - 로그아웃에 대한 설정을 할 수 있습니다. 코드에서는 로그아웃이 수행될 URL(logoutUrl), 로그아웃이 성공했을 때 포워딩될 URL(logoutSuccessUrl), 로그아웃을 성공했을 때 삭제될 쿠키값(deleteCookies), 설정된 세션의 무효화(invalidateHttpSession)를 수행하게끔 설정되어 있습니다.

 

addFilterBefore(filter, beforeFilter) - 첫 번째 인자보다 먼저 시작될 필터를 등록합니다. 

   - addFilterBefore(filter, CsrFilter.class) - 문자 인코딩 필터(filter)보다 CsrfFilter를 먼저 실행하도록 설정합니다.

 

SecurityConfig.java

OAuth2ClientProperties와 yml에서 설정했던 카카오 클라이언트 ID를 불러옵니다. @Configuration으로 등록되어 있는 클래스에서 @Bean으로 등록된 메서드의 파라미터로 지정된 객체들은 오토와이어링(autowiring)할 수 있습니다.

OAuth2ClientProperties에는 구글과 페이스북의 정보가 들어 있고 카카오는 따로 등록했기 때문에 @Value 어노테이션을 사용하여 수동으로 불러옵니다.

getRegistration() 메서드를 사용해 구글과 페이스북의 인증 정보를 빌드시켜줍니다.

registrations.add를 통해서 리스트에 카카오 정보를 추가합니다. 

 

UserArgumentResolver.java

HadlerMethodArgumentResolver는 전략 패턴의 일종으로 컨트롤러 메서드에서 특정 조건에 해당하는 파라미터가 있으면 생성한 로직을 처리한 후 해당 파라미터에 바인딩해주는 전략 인터페이스입니다. 따라서 AOP로 모든 메서드를 일일이 찾아보면서 파라미터에 바인딩하는 방법보다 훨씬 빠르고 만들기도 편리합니다.

 

소스코드

github - github.com/kgc0120/first_time_springboot2/tree/master/community_web

728x90
반응형

+ Recent posts