1. 캡차를 사용하기 위해 아래 링크로 접속해 사이트 등록을 진행한다. 

https://www.google.com/recaptcha/about/

 

 

2.  아래 이미지 순서로 수행한다!  캡챠는 여러 버전이 있으니 원하는바로 선택하면 된다. 

나는 체크박스 형태로 진행하기로 함! (체크박스를 원하면 그대로 따라하면 됨!)

 

 

도메인 부분에서 참고! 

로컬에서 테스트를 하려면 아래와 같이 localhost 등록도 해주어야한다. 

 

 

저장하면 비밀키와 사이트 키를 준다. 잘 저장해두자! 

 

 

이제 html를 작성해보자 

우선 캡차를 사용하기 위해 header에  스크립트를 추가해준다. 

<script src="https://www.google.com/recaptcha/api.js" async defer></script>

 

원하는 위치에 체크박스 캡챠 추가. 

@captcha.getSite() ---> 이부분에 앞서 발급받은 사이트 키를 입력해준다!! 

<div id="recaptcha" class="g-recaptcha" th:attr="data-sitekey=${@captcha.getSite()}" data-callback="recaptchaCallback"></div>

 

화면을 새로고침하면 캡차가 표시되는걸 볼 수 있다. 

 

 

이제 사용자가 캡챠 수행을 했는지 여부를 스크립트 단에서 확인해본다. 

캡차를 수행하게되면 grecaptcha.getResponse() 에 값이 들어오게 되는데 

이 값을 기준으로 수행여부를 가볍게 체크해본다. 

 

if(grecaptcha.getResponse() == "") {
	alert("캡챠를 수행하세요!");
}

 

본 비즈니스 로직을 타기 전 서버단에서도 한번 더 체크해준다. 

 grecaptcha.getResponse() 값을 다시 구글에 검증하는 로직이다. 

나의 경우 Interceptor을 만들어 캡챠수행 여부를 검증하고 정상적이지 않은 경우 튕겨내는 방식으로 작업을 진행했다. 

public static boolean verifyRecaptcha(String recaptcha) {
    	final String SECRET_KEY = "구글 비밀키"; // 비밀키 호출
    	final String RE_URL = "https://www.google.com/recaptcha/api/siteverify";// 인증할 URL
    	
		try {
			URL obj = new URL(RE_URL);
			HttpsURLConnection con = (HttpsURLConnection) obj.openConnection();
			con.setRequestMethod("POST");
			
			String postParams = "secret=" + SECRET_KEY + "&response=" + recaptcha;
			con.setDoOutput(true);
			
			DataOutputStream wr = new DataOutputStream(con.getOutputStream());
			wr.writeBytes(postParams);
			wr.flush();
			wr.close();

			BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
			String inputLine;
			StringBuffer response = new StringBuffer();

			while ((inputLine = in.readLine()) != null) {
				response.append(inputLine);
			}
			in.close();

			JsonReader jsonReader = Json.createReader(new StringReader(response.toString()));
			JsonObject jsonObject = jsonReader.readObject();
			jsonReader.close();
			
			return jsonObject.getBoolean("success"); //최종 Return 값 : true or false
			
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

 

 

 

 

<이전포스팅>

 

[Google 로그인] #2 FRONT 코드작성!

지난 포스팅에서 로그인 기능을 사용할 준비를 했다면 이제 직접 구현해보자! < 지난 포스팅! > [Google 로그인] #1 개발자 콘솔 가입! 1. 구글 개발자 콘솔에 로그인한다. console.developers.google.com/ Googl

genie-dev.tistory.com

 

Spring maven 환경에서 사용할

가이드 용도로 작업한거라 간단하게 기능만 짤라서 구현한 내용임! 

(시큐리티 적용 X)

 

순서는 이렇다~ 

1. 로그인페이지에서 구글 로그인 

2. 결과로 리턴받은 토큰을 서버로 전송 

3. 토큰을 이용해서 서버단에서 다시한번 사용자 정보 요청 

4. 프론트에서 넘어온 정보와 서버단에서 가져온 사용자 정보가 일치하는지 확인

5. 로그인 처리 or 내가 원하는 다른 작업을 진행하면 된다. 

 

pom.xml ( 필요한 기능들을 추가해준다. ) 

		<!--  새로 추가  -->
		<dependency>
		    <groupId>com.fasterxml.jackson.core</groupId>
		    <artifactId>jackson-core</artifactId>
		    <version>2.12.1</version>
		</dependency>
		
		<dependency>
		    <groupId>com.fasterxml.jackson.core</groupId>
		    <artifactId>jackson-databind</artifactId>
		    <version>2.12.1</version>
		</dependency>
		
		<dependency>
		    <groupId>com.fasterxml.jackson.core</groupId>
		    <artifactId>jackson-annotations</artifactId>
		    <version>2.12.1</version>
		</dependency>
		
		<dependency>
		    <groupId>org.codehaus.jackson</groupId>
		    <artifactId>jackson-mapper-asl</artifactId>
		    <version>1.9.13</version>
		</dependency>
				
		
		<dependency>
		    <groupId>com.google.code.gson</groupId>
		    <artifactId>gson</artifactId>
		    <version>2.8.6</version>
		</dependency>
		
		<dependency>
	     <groupId>com.google.api-client</groupId>
	     <artifactId>google-api-client</artifactId>
	     <version>1.31.2</version>
	   </dependency>
	   
		<dependency>
		    <groupId>com.google.api-client</groupId>
		    <artifactId>google-api-client-jackson2</artifactId>
		    <version>1.20.0</version>
		</dependency>
	  

 

VO 생성 ( 내가 받을 내용을 작성하면 되는데 테스트용이므로 간단하게 작성했다.)

public class UserVO {
	private String email;
	private String token;
	
	public String getToken() {
		return token;
	}

	public void setToken(String token) {
		this.token = token;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	} 
	
}

 

Controller 생성 ( 요청을 받을 컨트롤러를 작성한다)

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;


import com.me.genie.service.GoogleService;
import com.me.genie.vo.UserVO;

import java.io.IOException;

@Controller
public class GoogleController {
	
	@Autowired GoogleService googleService;
	
	/**
	 * Authentication Code를 전달 받는 엔드포인트
     * 구글 개발자 사이트에서 리턴url로 적었을 경우만 가져옴
     * 백엔드에서 받는 방법도 보여주고자 작성함
	 * @throws IOException 
	 * @throws JsonProcessingException
	 * @throws JsonMappingException
	 **/
	@RequestMapping(value = "/google/auth")
	public String googleAuth(Model model, @RequestParam(value = "code") String authCode) throws IOException{
		// 구글이 리턴해준 코드가 들어온다.
		System.out.println("AUtho code : " + authCode);
		googleService.getToken(authCode);
		return "/home";
	}
	
	
	/**
	 * 프론트로부터 ajax 요청을 받는다.
	 * @param user
	 * @return
	 */
	@RequestMapping(value = "/google/userinfo", produces = "application/json")
	@ResponseBody 
	public Map<String, Object> revokeToken(UserVO user) {
		Map<String, Object> result = new HashMap<String, Object>();
		result.put("res", googleService.tokenCheck(user));
		return result;

	}

}

 

Service ( 비즈니스 로직처리할 서비스 구현)

import com.google.gson.JsonElement;
import com.google.gson.JsonParser;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Collections;

import org.springframework.stereotype.Service;


import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;

import com.me.genie.service.GoogleService;
import com.me.genie.vo.UserVO;

@Service
public class GoogleService {
	final static String GOOGLE_AUTH_BASE_URL = "https://accounts.google.com/o/oauth2/v2/auth";
	final static String GOOGLE_TOKEN_BASE_URL = "https://oauth2.googleapis.com/token";
	final static String GOOGLE_REVOKE_TOKEN_BASE_URL = "https://oauth2.googleapis.com/revoke";
	final static String GOOGLE_GET_USER_INFO_URL = "https://www.googleapis.com/oauth2/v1/userinfo?access_token=";
	final static String clientId = "나의 클라이언트키";
	final static String clientSecret = "비밀키";
	
	 private static final HttpTransport transport = new NetHttpTransport();
	 private static final JsonFactory jsonFactory = new JacksonFactory();
	
	 /**
	 * 백엔드단에서 토큰을 얻어온다.
	  * @param authCode
	  * @return access_Token
	  * @throws IOException
	  */
	public String getToken(String authCode) throws IOException {
		
		/**************************************
         * Access 토큰을 가져오기 위한 설정
         *************************************/
		URL url = new URL(GOOGLE_TOKEN_BASE_URL);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        conn.setDoOutput(true);

        
        /**************************************
         * 파라메터 설정
         *************************************/
        StringBuffer sbf = new StringBuffer();
        sbf.append("code=");sbf.append(authCode);
        sbf.append("&client_id=");sbf.append(clientId);
        sbf.append("&client_secret=");sbf.append(clientSecret);
        sbf.append("&redirect_uri=");sbf.append("http://localhost:8080/google/auth");
        sbf.append("&grant_type=");sbf.append("authorization_code");
        String  parameterString = sbf.toString();
		
        
        /**************************************
         * 요청을 보내고 받을 스트림 생성
         *************************************/
		BufferedOutputStream bous = new BufferedOutputStream(conn.getOutputStream());
		bous.write(parameterString.getBytes()); 
		bous.flush(); 
		bous.close();
		
		BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
		
		/**************************************
         * 받아온 데이터를 sb에 저장
         *************************************/
		StringBuilder sb = new StringBuilder(); 
		String line;
		while ((line = br.readLine()) != null) { 
			sb.append(line); 
		}
		
		/**************************************
         * 받아온 데이터에서 토큰 추출
         *************************************/
		String access_Token ="";
		if (conn.getResponseCode() == 200) { 
            JsonParser parser = new JsonParser();
            JsonElement element = parser.parse(sb.toString());
            access_Token = element.getAsJsonObject().get("access_token").getAsString();
            System.out.println("access_token : " + access_Token);
            
            if(access_Token!=null) {
                /***사용자 정보 요청 **/
            	userinfo(access_Token);
            }
		}
		return access_Token;
	}
	
	/**
	 * access_token 이용하여 사용자 정보를 가져온다.
	 * @param access_token
	 */
	public void userinfo(String access_token) {
		try { 
			
			/**************************************
	         * 사용자 정보를 가져오기 위한 셋팅
	         *************************************/
	        URL url = new URL(GOOGLE_GET_USER_INFO_URL+access_token);
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setRequestMethod("GET"); 
			conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
			conn.setDoOutput(true);
			
			
			/**************************************
	         * 요청을 보내고 받을 스트림 생성
	         *************************************/
			BufferedOutputStream bous = new BufferedOutputStream(conn.getOutputStream());
			bous.flush(); 
			bous.close();
			
			BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
			StringBuilder sb = new StringBuilder(); String line;
	  
			while ((line = br.readLine()) != null) { 
				sb.append(line); 
			}
			 
			/**************************************
	         * 받아온 데이터에서 출력
	         *************************************/
			if (conn.getResponseCode() == 200) { 
				System.out.println(sb.toString()); 
			}
			
		} catch (Exception e) {
			System.out.println("ERROR. . . PLEASE CHECK ... [GoogleService.userinfo]");
			e.printStackTrace();
		}
	}
	
	/**
	 * 사용자단에서 가져온 토큰값으로 
	 * 유효한사용자인지, 요청온 이메일은 맞는지 확인한다.
	 * @param user
	 * @return 유효여부
	 */
	public boolean tokenCheck(UserVO user) {
		boolean res = false;
		try {
			
			/**************************************
	         * 사용자 정보를 가져오기 위해 구글에서 
	         * 제공하는 설정 셋팅
	         *************************************/
			GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
			    .setAudience(Collections.singletonList(clientId))
			    .build();
		
			/**************************************
	         * 프론트 단에서 로그인 후 받아온 코드 설정 후 
	         * 사용자 정보를 가져온다.
	         *************************************/
			GoogleIdToken idToken = verifier.verify(user.getToken());
			
			// 사용자 정보가 존재하는지 확인
			if (idToken != null) {
			  // 사용자 정보가 담긴 데이터를 가져온다.
			  Payload payload = idToken.getPayload();
		
			  // 사용자 고유 ID 가져온다.
			  String userId = payload.getSubject();
			  System.out.println("User ID: " + userId);
		
			  // 그외 사용자 정보를 가져온다.
			  String email = payload.getEmail();
			  String name = (String) payload.get("name");
			  String pictureUrl = (String) payload.get("picture");
			  String locale = (String) payload.get("locale");
			  String familyName = (String) payload.get("family_name");
			  String givenName = (String) payload.get("given_name");
			  
			  /**************************************
	          * 프론트 단에서 로그인을 시도한 이메일과, 코드를 통해 가져온 정보가 일치하는지 확인한다. 
	          *************************************/
			  if(user.getEmail().equals(email)) { 
				  res = true; 
			  }
			  
			} else {
			  System.out.println("Invalid ID token.");
			}
			
		} catch (Exception e) {
			System.out.println("ERROR. . . PLEASE CHECK ... [GoogleService.userinfo]");
			e.printStackTrace();
		}
		return res;
	}
}

 

home.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
	<title>Home</title>
	<script src="https://apis.google.com/js/platform.js" async defer></script>
	<meta name="google-signin-client_id" content="{발급받인 클라이언트 아이디}.apps.googleusercontent.com"></meta>
</head>
<body>

  
    <h1>로그인</h1>
    <hr>

    <form action="/user/login" method="post">
        <input type="text" name="username" placeholder="이메일 입력해주세요">
        <input type="password" name="password" placeholder="비밀번호">
        <button type="submit">로그인</button>
        
        <!-- 구글 로그인  -->
		<div class="g-signin2" data-onsuccess="onSignIn"></div>
		<!-- 구글 아웃 -->
		<a href="#" onclick="signOut()">구글 로그아웃</a>
        
        
  		
    </form>
	
    
    <script src="/resources/css/bower_components/jquery/dist/jquery.min.js"></script>
	<script src="/resources/css/bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
	<script src="/resources/css/dist/js/adminlte.min.js"></script>
	<script src="/resources/js/utils/easy_ui/jquery.easyui.min.js"></script>
    <script>
	function onSignIn(googleUser) { 
		
    	var profile = googleUser.getBasicProfile(); 
		/*
    	console.log('ID: ' + profile.getId()); // 이건 백엔드로 보내면 안됨! 보안의 위험이 있음. 
    	console.log('Name: ' + profile.getName()); 
    	console.log('Image URL: ' + profile.getImageUrl()); 
    	console.log('Email: ' + profile.getEmail()); // This is null if the 'email' scope is not present.
		console.log(googleUser.getAuthResponse().id_token); // 서버에 던질땐 보안을 위해 이값으로 던져준다.
		*/
		
		var email = profile.getEmail();
		var token = googleUser.getAuthResponse().id_token;
    	$.ajax({
    	    url:'/google/userinfo', 
    	    type:'post', 
    	    data:{'token': token, 'email': email}, 
    	    success: function(data) {
    	        if(data.res) { 
	    	        alert("OK");
       	        } else {
       	        	alert("비정상로그인 접근입니다.");
           	    }
    	    },
    	    error: function(err) {
    	        //서버로부터 응답이 정상적으로 처리되지 못햇을 때 실행
    	    }
    	});
    }
	 
	function signOut() { 
    	var auth2 = gapi.auth2.getAuthInstance(); 
    	auth2.signOut().then(function () {
        	 self.location="로그아웃할 url"; 
        }); 
   	 } 
  	</script>

   
</body>
</html>


 

1. 구글 개발자 콘솔에 로그인한다. 

console.developers.google.com/

 

Google Cloud Platform

하나의 계정으로 모든 Google 서비스를 Google Cloud Platform을 사용하려면 로그인하세요.

accounts.google.com

 

 

2.  접속하면 동의란이 뜨는데 체크 후 계속하기 버튼을 누른다. 

 

3. 프로젝트를 생성해준다. 

 

4. 프로젝트 이름을 입력하고 만들기! 

 

5. 검색란에 google api를 검색해서 클릭한다. 

 

6. API 사용버튼 클릭! 

 

 

7. 좌측 메뉴에서 사용자 인증정보 클릭-> 동의화면 구성 클릭

 

8.  앱이름과 이메일, 로고 파일등을 입력한다. 테스트용으로 사용할거라 localhost로 설정! 

 

9.  좌측 메뉴에 사용자 인증정보 메뉴 > 사용자 인증정보 만들기 > 클라이언트 ID 클릭 

 

10. 양식 작성 

 

11. 만들기를 누르면 키가 생성되는데 잘 저장해둔다! 

12.  리다이렉션 받을 uri를 적어주면된다~ 

+ Recent posts