반응형

스프링 부트와 OAuth2

Spring Boot And OAuth2

(원문소스: https://spring.io/guides/tutorials/spring-boot-oauth2/)


이 가이드에서 OAuth2와 Spring Boot를 사용해 어떻게 하면 "소셜 로그인"의 다양한 일을 하는 예제를 만들 수 있는 지 보여줄 것이다. 간단한 하나의 싱글사인온 제공자에 연결해보는 걸로 시작하여, Facebook 이나 Github과 같은 authentication 제공자와 함께 OAuth2 Authorization Server를 스스로 돌리는 일을 해볼것이다. 예제들은 백엔드로 모두 스프링 부트와 스프링 OAuth를 사용한 단일 페이지 앱이 될 것이며 프론트엔드로 모두 AngularJS 를 사용하였다. 하지만 자바스크립트단의 코드나 서버의 랜더링사용은 최소화 하였다.

각각 새로운 기능을 추가해놓은 몇가지 예제들이다:

  • simple: 매우 기본적인 정적 앱으로 그냥 하나의 홈페이지와 스프링부트의 @EnableOAuth2Sso를 통해 무작위 로그인을 한다 (홈페이지를 방문하면 자동으로 페이스북으로 리다이렉트 될 것이다)

  • click: 사용자가 로그인을 클릭할 수 있는 명시적 링크를 추가하였다.

  • logout: 인증받은 사용자를 위한 로그아웃 링크를 추가하였다.

  • manual @EnableOAuth2Sso 어노테이션을 사용하지않고 수동으로 설정하여 똑같이 동작시켜본다.

  • gitub: 두번째 로그인 제공자로서 Github을 추가하여 사용자는 홈페이지에서 어느것을 사용할 지 고를 수 있다.

  • auth-server스스로 토큰을 발행할 수 있지만 여전히 인증을 위해 외부 OAuth2 제공자를 사용할 수 있는 완전무결한fully-fledged OAuth2  Authorization 서버를 돌린다. 

  • custom-error Github API에 기반한 커스텀 인증과, 비인증 사용자를 위한 에러 메세지를 추가하였다.

이들은 각각 IDE에서 불러올 수 있으며, 앱을 시작할 수 있는 SocialApplication 메인 클래스가 있다. 이들 모두 http://localhost:8080 로 홈페이지에 접근할 수 있다.( 로그인을 하고 그 내용을 보려면 최소한 페이스북 계정이 필요하다). 또한, gmvn spring-boot:run를 사용하여 커맨드라인상에서 앱을 돌리거나, mvn package 를 통해 jar파일을 빌드하고 java -jar target/*.jar 로도 돌릴 수 있다. 프로젝트 상위레벨에 있는 wrapper를 사용하면 메이븐을 설치하지않다도 된다. 예를 들면:

$ cd simple
$ ../mvnw package
$ java -jar target/*.jar
 모든 앱은 localhost:8080

에서 동작한다. 페이스북과 Github에 이 주소로 OAuth2 클라이언트를 등록했기 때문이다. 다른 호스트나 포트로 돌리려면 스스로 각각 앱을 등록하고 config 파일에 해당 인증정보들을 넣어줘야한다. 기본설정값을 사용하면 localhost로 돌린다고 당신의 페이스북이나 Github 인증정보가 누출되거나 위험해지지않는다. 하지만 당신이 인터넷에 무엇을 노출할지 조심해야한다. 공개 소스 컨트롤에 당신의 앱을 등록하지 않아야한다.

페이스북으로 싱글 사인온 하기 Single Sign On With Facebook

이 섹션에서, 우리는 인증을 위해 페이스북을 사용하는 최소한의 어플리케이션을 만들것이다. 이는 스프링 부트의 자동설정을 사용하면 매우 쉽다. 

새 프로젝트 만들기

먼저 스프링 부트 어플리케이션을 만들어야 한다. 이를 위한 수많은 방법이 있지만, 가장 쉬운 것은 http://start.spring.io 를 방문하여 빈 프로젝트를 만드는 것이다. (시작점으로서 "Web" 의존성을 골라주자). 커맨드라인으로 아래와 같이하면 똑같이 만들 수 있다:

$ mkdir ui && cd ui
$ curl https://start.spring.io/starter.tgz -d style=web -d name=simple | tar -xzvf -

이제 당신이 선호하는 IDE에서 이 프로젝트를 불러올 수 있다. (기본적으로 보통의 메이븐 자바프로젝트다) 또는 파일 작업을 하고 그냥 커맨드라인에서 "mvn"을 사용해도 된다.

홈페이지 추가하기

새 프로젝트의 "src/main/resources/static" 폴더에 index.html파일을 만들자. 몇몇의 스타일시트와 자바스크립트를 링크해줘야하며 그 결과는 다음과 같다:

index.html
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <title>Demo</title>
    <meta name="description" content=""/>
    <meta name="viewport" content="width=device-width"/>
    <base href="/"/>
    <link rel="stylesheet" type="text/css" href="/webjars/bootstrap/css/bootstrap.min.css"/>
    <script type="text/javascript" src="/webjars/jquery/jquery.min.js"></script>
    <script type="text/javascript" src="/webjars/bootstrap/js/bootstrap.min.js"></script>
</head>
<body>
	<h1>Demo</h1>
	<div class="container"></div>
</body>
</html>

이 소스의 무엇도 OAuth2 로그인 기능과 무관하지만 우리는 홈페이지에 약간의 기본적인 기능을 시작할 수 있을 뿐아니라 멋지게 보이는 UI 를 원한다.

앱을 시작하고 홈페이지를 로드하면, 스타일 시트가 로드되지 않았다는 걸 알 수 있을 것이다. 이제 그들을 아래와 같이 의존성을 추가해줌으로서 해결할 수 있다:

pom.xml
<dependency>
	<groupId>org.webjars</groupId>
	<artifactId>angularjs</artifactId>
	<version>1.4.3</version>
</dependency>
<dependency>
	<groupId>org.webjars</groupId>
	<artifactId>jquery</artifactId>
	<version>2.1.1</version>
</dependency>
<dependency>
	<groupId>org.webjars</groupId>
	<artifactId>bootstrap</artifactId>
	<version>3.2.0</version>
</dependency>
<dependency>
	<groupId>org.webjars</groupId>
	<artifactId>webjars-locator</artifactId>
</dependency>

우리는 트위터 부트스트랩과 (우리가 지금 당장 써야하는) jQuery, 거기에 나중에 쓸 AngularJS를 추가했다. 다른 의존성은 webjars "locator"로 webjars 사이트에 의해 라이브러리로서 제공받는 것이고 이것은 스프링에 의해 정확한 버전을 알 필요없이(그렇기 때문에 index.html에서 버전없는 /webjar/all}링크를 사용했다webjars의 정적인 어셋을 위치locate하는데 사용된다. 이 webjar locator를 활성화하려면 어플리케이션의 application.properties에서 Spring MVC 리소스 체인을 활성화시켜줘야한다:

application.properties
spring.resources.chain.enabled: true

이 수정을 통해 이제 우리는 이뻐보이는 홈페이지를 가지게 되었다.

어플리케이션 보호하기 Securing the Application

어플리케이션을 안전하게 만드려면, 스프링 시큐리티 의존성을 추가해주면 된다. 그러면 기본적으로 HTTP Basic으로 보호될 것이다. 따라서 우리가 (페이스북으로 위임하는) "소셜" 로그인을 만드려고 하므로, Spring Security OAuth2 의존성 또한 추가해줘야한다:

pom.xml
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.security.oauth</groupId>
	<artifactId>spring-security-oauth2</artifactId>
</dependency>

페이스북으로의 링크를 만드면, 메인클래스에서 @EnableOAuth2Sso 어노테이션을 해줘야한다:

SocialApplication.java
@SpringBootApplication
@EnableOAuth2Sso
public class SocialApplication {

  ...

}

그리고 약간의 설정이 필요하다 (더 나은 식별성을 위해 application.properties을 YAML 으로 변환하였다):

application.yml
security:
  oauth2:
    client:
      clientId: 233668646673605
      clientSecret: 33b17e044ee6a4fa383f46ec6e28ea1d
      accessTokenUri: https://graph.facebook.com/oauth/access_token
      userAuthorizationUri: https://www.facebook.com/dialog/oauth
      tokenName: oauth_token
      authenticationScheme: query
      clientAuthenticationScheme: form
    resource:
      userInfoUri: https://graph.facebook.com/me
...

이 설정은 페이스북의 개발자사이트에 등록된 클라이언트 앱을 참조한다. 당신은 당신의 앱에서 리다이렉트할 곳을 등록해줘야한다. (우리의 경우 Home page). 이것은 "localhost:8080"으로 등록되었는데, 이 주소로 돌아가는 앱에서만 작동한다.

이 수정으로 앱을 다시 돌리고 http://localhost:8080의 홈페이지를 방문해보자. 홈페이지 대신, 당신은 페이스북 로그인으로 리다이렉트될 것이다. 로그인하려고 인가authorization를 수락하면, 당신의 로컬 앱으로 다시 리다이렉트되어 돌아와지고 홈페이지가 보여질 것이다. 만일 페이스북 로그인이 되어있는 상태면, 브라우저를 완전히 새롭게 열어 쿠키도 없고 캐시된 데이터가 없더라고 이 로컬앱에서 재인증할 필요없다. (이것이 싱글사이온의 의미이다)

당신이 이 섹션의 예제 어플리케이션을 돌리는 중이라면, 브라우저의 쿠키와 HTTP Basic credentials의 캐시를 지웠는지 먼저 확인하자. 크롬의 incognito window를 사용하는 것이 가장 좋은 방법이다.

이 예제의 접근을 승인하는 것grant access은 안전하다. 로컬에서만 동작하고 있는 이 앱에서만 토큰을 사용할 수 있고 범위scope도 제약적이기 때문이다. 당신이 이와 같은 절차를 거치는 앱을 로그인할 때, 무엇을 승인해야하는지 반드시 살펴봐야한다: 당신이 불편해할 만큼의 권한을 요구할 수도 있기때문이다. (예를 들면, 당신의 개인정보를 수정할 수 있는 권한을 요구할 수 있다.)

방금 뭔일 있었나? What Just Happened?

당신이 방금 만든 이 앱은, OAuth2 용어로, 클라이언트 어플리케이션이다. 그리고 이 앱은 페이스북(인가서버Authorization Server)로부터 억세스토큰access token을 받기위해 authorization code grant를 사용했다. 그 후 당신의 로그인ID와 이름을 포함한 (당신이 허용해준) 몇가지 개인 정보를 페이스북에 요청하기 위해 억세스토큰을 사용했다. 이 단계까지 페이스북은 당신이 보낸 토큰을 디코딩하고 사용자의 정보에 접근하는 앱의 권한을 체크하는 등등의 리소스 서버로서 역할을 하고 있다. 이 단계가 성공적으로 완료되면, 당신의 앱은 사용자 정보를 스프링 시큐리티 컨텍스트Spring security context안에 넣음으로서 당신을 인증할 것이다.

(크롬의 F12누르면 보이는) 브라우저 도구를 열고 네트워크 트래픽을 따라가보면, 페이스북으로 리다이렉트되어 가고오고 하는것을 확인할 수 있으며 최종적으로 새 Set-Cookie 헤더를 가지고 홈페이지로 되돌아와진다. 이 쿠키(기본값으로JSESSIONID)는 스프링(또는 어느 서블릿 기반의) 어플리케이션에서 당신의 인증 상세정보를 위한 하나의 토큰이다.

이제 우리는, 어떠한 정보를 보기위해 사용자가 페이스북과 같은 외부 제공자로 인증해야하는 측면에서, 안전한 어플리케이션을 가지게 되었다. 우리는 웹사이트에 매번 이를 사용하려는게 아니라 기본 식별, 그리고 당신의 사이트에 서로 다른 사용자간에 컨텐트를 구별하기 위한 목적으로 이는 오늘날 이러한 종류의 인증이 왜 인기가 많은가를 설명하는 훌륭한 출발점이 될 것이다. 다음 섹션에서 우리는 어플리케이션에 약간의 기본 기능들을 추가하고, 사용자가 처음 페이스북으로 리다이렉트 할 때 언제 그리고 무엇을 하는지 조금더 구체적으로 알아볼 것이다.


반응형

+ Recent posts