본문 바로가기
기술&교육

Google Oauth2 (SSO) 가이드

by 베어그릴스 2022. 12. 6.
반응형

Oauth란?

 

SSO는 서비스이고, Oauth는 규약(프로토콜) 이다.

요식업 서비스에는 배송규약(프로토콜)이 준비 되어있는 것처럼 말이다.

 

SSO(서비스)는 OATUH(프로토콜) 방식을 이용해서 설계 되어질 수 있다.

 

실제 개발에 참조한 블로그 :

Google OAuth 사용법

 

oAuth2를 이용하기 위해서는 먼저 Google console에 접속하셔서 어플리케이션 등록을 해야합니다.

google console - https://console.developers.google.com

 

google console 접속 → 어플리케이션 등록

 

 

애플리케이션 유형 : 웹 애플리케이션

 
 
 

위 승인된 리디렉션 URI 가 많은 이유는 html 과 서블릿으로 둘다 테스트 했기 때문에 그렇다.

보통 클라이언트 아이디와 클라이언트 비밀번호는 민감한 정보이므로 js나 html에 두지 말고 java로 개발한다.

 

웹 어플리케이션에서 로그인 정보를 사용할 생각이기 때문에 웹 어플리케이션을 선택하고 제한사항으로는 일단 로컬에서 테스트하기 때문에 「http://localhost」 혹은 「http://localhost:8080」를 넣는다.

먼저 apache에서 html로 테스트를 한 후에 자바 서블릿으로도 테스트를 할 생각이기 때문에 기본 포트인 8080도 등록했다.

 

그리고 승인된 리디렉션 URI는 로그인이 완료되면 token을 보내는 URI입니다.

 

기본적으로 OAuth의 흐름은 아래와 같다.

 

생성을 하면 클라이언트 ID와 보안 키가 발급됩니다.

이제 톰켓에서 html과 javascript로 인증을 해보겠습니다. (참고로 file을 브라우져에서 띄울 경우는 리디렉션 주소 설정이 어렵기 때문에 apache로 테스트하는게 좋을 듯싶습니다.)

인증하는 방법에는 redirect로 하는 방법과 google 라이브러리를 이용하는 방법이 있습니다.

 

먼저 redirect로 하는 방법을 알아보겠습니다.

 

index.html

<!DOCTYPE html>
<html>
<head>
<title>Insert title here</title>
</head>
<body>
  <input type="button" id="loginBtn" value="login">
  <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
  <script>
    $("#loginBtn").click(function(){
      location.href="https://accounts.google.com/o/oauth2/auth?client_id="+
                "클라이언트 ID를 여기에 넣습니다."+
                "&redirect_uri="+
                "http://localhost/redirect.html" +
                "&response_type=code&scope=https://www.googleapis.com/auth/userinfo.email&approval_prompt=force&access_type=offline";
    });
  </script>
</body>
</html>

위 index에서 submit 버튼을 누르면 location.href로 인증 코드를 발급받는다.

redirect.html

<!DOCTYPE html>
<html>
<head>
<title>Insert title here</title>
</head>
<body>
  <form method="POST" action="https://accounts.google.com/o/oauth2/token">
    <!-- 로그인으로 얻은 code를 여기에 넣는다. -->
    <input type="text" name="code"> <br />
    <!-- 클라이언트 ID를 넣는다. -->
    <input type="text" name="client_id" value="클라이언트 ID"> <br />
    <!-- 클라이언트 보안 키를 넣는다. -->
    <input type="text" name="client_secret" value="클라이언트 보안 key"> <br />
    <!-- 등록한 리디렉트 주소를 여기에 넣는다. -->
    <input type="text" name="redirect_uri" value="http://localhost/redirect.html"> <br />
    <!-- 고정값 -->
    <input type="text" name="grant_type" value="authorization_code"> <br />
    <input type="submit">
  </form>
  <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
  <script>
    // 주소 창에 있는 parameter를 취득한다.
    function getParameter(name){
      var list = location.search.substring(1).split('&');
      for(var i=0;i<list.length;i++){
        var data = list[i].split('=');
        if(data.length === 2){
          if(data[0] === name){
            return data[1];
          }
        }
      }
      return null;
    }
    // 파라미터 code를 취득하고 URL 디코딩해서 input code에 넣는다.
    $("input[name=code]").val(decodeURIComponent(getParameter('code')));
  </script>
</body>
</html>

발급받은 인증 코드로 token으로 변환한다.

<!DOCTYPE html>
<html>
<head>
<title>Insert title here</title>
</head>
<body>
  <form method="GET" action="https://www.googleapis.com/oauth2/v1/userinfo">
    <!-- 받은 인증 코드로 id 정보를 얻는다.. -->
    <input type="text" name="access_token">
    <input type="submit">
  </form>
</body>
</html>

여기까지 html를 작성하고 apache또는 톰켓으로로 실행해 보겠습니다.

 

주소창에 URL 입력후 Login 버튼 클릭

계정을 선택해서 로그인을 합니다.

제출 버튼 클릭

그럼 인증 코드가 발급되서 가장 위 Textbox에 입력된다. 여기서 다시 제출 버튼을 누른다.

 

그럼 토큰이 발급된 것을 확인할 수 있습니다. 여기서 가장 위 access_token을 가지고 id정보를 가져옵니다.

userinfo.html로 가서 access_token을 넣고 제출 버튼을 누릅니다.

그럼 ID와 Email 주소 사진정보등을 얻어올 수 있습니다.

그럼 실제 Java servlet에서는 HttpConnection을 이용해서 사용하는데 구현해 보겠습니다.

구현은 redirect 형식의 html과 비슷한데 redirect 부분과 유저 정보를 취득하는 부분을 좀 더 안전하게 서블릿에서 HttpConnection를 이용하는 것 뿐입니다.

 

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF8" pageEncoding="UTF8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF8">
<title>Insert title here</title>
</head>
<body>
  <input type="button" id="loginBtn" value="login">
  <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
  <script>
    $("#loginBtn").click(function(){
      location.href="https://accounts.google.com/o/oauth2/auth?client_id="+
                "클라이언트ID"+
                "&redirect_uri="+
                "http://localhost:8080/redirect" +
                "&response_type=code&scope=https://www.googleapis.com/auth/userinfo.email&approval_prompt=force&access_type=offline";
    });
  </script>
</body>
</html>

Toek.java

class Token {
  private String access_token;
  private int expires_in;
  private String refresh_token;
  private String scope;
  private String token_type;
  private String id_token;
 
  public String getAccess_token() {
    return access_token;
  }
 
  public void setAccess_token(String access_token) {
    this.access_token = access_token;
  }
 
  public int getExpires_in() {
    return expires_in;
  }
 
  public void setExpires_in(int expires_in) {
    this.expires_in = expires_in;
  }
 
  public String getRefresh_token() {
    return refresh_token;
  }
 
  public void setRefresh_token(String refresh_token) {
    this.refresh_token = refresh_token;
  }
 
  public String getScope() {
    return scope;
  }
 
  public void setScope(String scope) {
    this.scope = scope;
  }
 
  public String getToken_type() {
    return token_type;
  }
 
  public void setToken_type(String token_type) {
    this.token_type = token_type;
  }
 
  public String getId_token() {
    return id_token;
  }
 
  public void setId_token(String id_token) {
    this.id_token = id_token;
  }
 
}

 

Redirect.java

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.URL;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.gson.Gson;
import javax.net.ssl.HttpsURLConnection;
 
@WebServlet("/redirect")
public class Redirect extends HttpServlet {
 
  private static final long serialVersionUID = 1L;
 
  public Redirect() {
    super();
  }
 
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String code = request.getParameter("code");
    String query = "code=" + code;
    query += "&client_id=" + "클라이언트 ID";
    query += "&client_secret=" + "클라이언트 보안 키";
    query += "&redirect_uri=" + "등록한 리디렉트 주소";
    query += "&grant_type=authorization_code";
 
    String tokenJson = getHttpConnection("https://accounts.google.com/o/oauth2/token", query);
    System.out.println(tokenJson.toString());
    Gson gson = new Gson();
    Token token = gson.fromJson(tokenJson, Token.class);
 
    String ret = getHttpConnection("https://www.googleapis.com/oauth2/v1/userinfo?access_token=" + token.getAccess_token());
    System.out.println(ret);
  }
 
  private String getHttpConnection(String uri) throws ServletException, IOException {
    URL url = new URL(uri);
    HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
    conn.setRequestMethod("GET");
    int responseCode = conn.getResponseCode();
    System.out.println(responseCode);
 
    String line;
    StringBuffer buffer = new StringBuffer();
    try (InputStream stream = conn.getInputStream()) {
      try (BufferedReader rd = new BufferedReader(new InputStreamReader(stream))) {
        while ((line = rd.readLine()) != null) {
          buffer.append(line);
          buffer.append('\r');
        }
      }
    } catch (Throwable e) {
      e.printStackTrace();
    }
    return buffer.toString();
  }
 
  private String getHttpConnection(String uri, String param) throws ServletException, IOException {
    URL url = new URL(uri);
    HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
    conn.setRequestMethod("POST");
    conn.setDoOutput(true);
    try (OutputStream stream = conn.getOutputStream()) {
      try (BufferedWriter wd = new BufferedWriter(new OutputStreamWriter(stream))) {
        wd.write(param);
      }
    }
    int responseCode = conn.getResponseCode();
    System.out.println(responseCode);
 
    String line;
    StringBuffer buffer = new StringBuffer();
    try (InputStream stream = conn.getInputStream()) {
      try (BufferedReader rd = new BufferedReader(new InputStreamReader(stream))) {
        while ((line = rd.readLine()) != null) {
          buffer.append(line);
          buffer.append('\r');
        }
      }
    } catch (Throwable e) {
      e.printStackTrace();
    }
    return buffer.toString();
  }
 
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    doGet(request, response);
  }
 
}

 

서블릿 맵핑

아래는 개발환경 마다 다를수 있으니 참고

    <servlet>
        <description>Redirect</description>
        <display-name>Redirect</display-name>
        <servlet-name>Redirect</servlet-name>
        <servlet-class>com.jnj.jims.kr.web.Redirect</servlet-class>
        <load-on-startup>4</load-on-startup>
    </servlet>
    
    <servlet-mapping>
      <servlet-name>Redirect</servlet-name>
      <url-pattern>/redirect</url-pattern>
    </servlet-mapping>

 

index.jsp

로그인 버튼 클릭

 

콘솔로그 메시지

다른 포털 사이트의 OAuth 형식도 구글의 형식과 많이 비슷합니다. 다만 라이브러리를 지원하는 데가 있고 지원하지 않는 곳이 있는데 Redirect 방식의 95%비슷하니 참고해서 사용하면 된다.

 

WebExample.zip
0.01MB
Redirect OAuth.zip
0.00MB

반응형

댓글