[Spring] 네이버 로그인 API/JSON to String

Posted by 신희준 on November 30, 2017



2017 - 11 - 30 (목)


네이버 로그인


1 . 네이버 개발자 센터에서 어플리케이션을 등록합니다.

2 . 네이버 어플리케이션 ID 와 SECRET 코드를 저장해 둡니다.

3 . pom.xml 에 아래 코드를 추가

<dependency>
  <groupId>com.github.scribejava</groupId>
  <artifactId>scribejava-core</artifactId>
  <version>3.3.0</version>
</dependency>
<dependency>
  <groupId>commons-lang</groupId>
  <artifactId>commons-lang</artifactId>
  <version>2.3</version>
</dependency>
<dependency>
  <groupId>commons-logging</groupId>
  <artifactId>commons-logging</artifactId>
  <version>1.1.3</version>
</dependency>

4 . com/bitproject/naver/NaverLoginBO 생성

package com.bitproject.naver;

import java.io.IOException;
import java.util.UUID;

import javax.servlet.http.HttpSession;

public class NaverLoginBO {
	private final static String CLIENT_ID = "네이버 앱아이디";
	private final static String CLIENT_SECRET = "네이버 시크릿코드";
	private final static String REDIRECT_URI = "http://localhost/login/callback";
	private final static String SESSION_STATE = "oauth_state";
	/* 프로필 조회 API URL */
	private final static String PROFILE_API_URL = "https://openapi.naver.com/v1/nid/me";

	/* 네아로 인증  URL 생성  Method */
	public String getAuthorizationUrl(HttpSession session) {

		/* 세션 유효성 검증을 위하여 난수를 생성 */
		String state = generateRandomString();
		/* 생성한 난수 값을 session에 저장 */
		setSession(session,state);

		/* Scribe에서 제공하는 인증 URL 생성 기능을 이용하여 네아로 인증 URL 생성 */
		OAuth20Service oauthService = new ServiceBuilder()
				.apiKey(CLIENT_ID)
				.apiSecret(CLIENT_SECRET)
				.callback(REDIRECT_URI)
				.state(state)
				.build(NaverLoginApi.instance());

		return oauthService.getAuthorizationUrl();
	}

	/* 네아로 Callback 처리 및  AccessToken 획득 Method */
	public OAuth2AccessToken getAccessToken(HttpSession session, String code, String state) throws IOException{

		/* Callback으로 전달받은 세선검증용 난수값과 세션에 저장되어있는 값이 일치하는지 확인 */
		String sessionState = getSession(session);
		if(StringUtils.pathEquals(sessionState, state)){

			OAuth20Service oauthService = new ServiceBuilder()
					.apiKey(CLIENT_ID)
					.apiSecret(CLIENT_SECRET)
					.callback(REDIRECT_URI)
					.state(state)
					.build(NaverLoginApi.instance());

			/* Scribe에서 제공하는 AccessToken 획득 기능으로 네아로 Access Token을 획득 */
			OAuth2AccessToken accessToken = oauthService.getAccessToken(code);
			return accessToken;
		}
		return null;
	}

	/* 세션 유효성 검증을 위한 난수 생성기 */
	private String generateRandomString() {
		return UUID.randomUUID().toString();
	}

	/* http session에 데이터 저장 */
	private void setSession(HttpSession session,String state){
		session.setAttribute(SESSION_STATE, state);		
	}

	/* http session에서 데이터 가져오기 */
	private String getSession(HttpSession session){
		return (String) session.getAttribute(SESSION_STATE);
	}

	/* Access Token을 이용하여 네이버 사용자 프로필 API를 호출 */
	public String getUserProfile(OAuth2AccessToken oauthToken) throws IOException{

		OAuth20Service oauthService =new ServiceBuilder()
    			.apiKey(CLIENT_ID)
    			.apiSecret(CLIENT_SECRET)
    			.callback(REDIRECT_URI).build(NaverLoginApi.instance());

    	OAuthRequest request = new OAuthRequest(Verb.GET, PROFILE_API_URL, oauthService);
		oauthService.signRequest(oauthToken, request);
		Response response = request.send();
		return response.getBody();
	}
}

5 . com/bitproject/naver/NaverLoginApi 생성

package com.bitproject.naver;

import com.github.scribejava.core.builder.api.DefaultApi20;

public class NaverLoginApi extends DefaultApi20 {
	protected NaverLoginApi() {
	}

	private static class InstanceHolder {
		private static final NaverLoginApi INSTANCE = new NaverLoginApi();
	}

	public static NaverLoginApi instance() {
		return InstanceHolder.INSTANCE;
	}

	@Override
	public String getAccessTokenEndpoint() {
		return "https://nid.naver.com/oauth2.0/token?grant_type=authorization_code";
	}

	@Override
	protected String getAuthorizationBaseUrl() {
		return "https://nid.naver.com/oauth2.0/authorize";
	}
}

6 . servlet-context.xml 에 빈 등록

<beans:bean id="naverLoginBO" class="com.bitproject.naver.NaverLoginBO" />

7 . userController에 user/naverLogin 에 매핑되는 매서드와 user/callback 추가

private NaverLoginBO naverLoginBO;
		private String apiResult = null;
		/* NaverLoginBO */
		@Inject
		private void setNaverLoginBO(NaverLoginBO naverLoginBO) {
			this.naverLoginBO = naverLoginBO;
		}

		@RequestMapping(value="/naverLogin", method = RequestMethod.GET)
		public ModelAndView login(HttpSession session) {
			/* 네아로 인증 URL을 생성하기 위하여 getAuthorizationUrl을 호출 */
			String naverAuthUrl = naverLoginBO.getAuthorizationUrl(session);
			System.out.println("controller 호출");
			return new ModelAndView("user/naverLogin", "url", naverAuthUrl);
		}

		@RequestMapping(value="/callback",method = RequestMethod.GET)
		public ModelAndView callback(@RequestParam String code, @RequestParam String state, HttpSession session) throws IOException {
			/* 네아로 인증이 성공적으로 완료되면 code 파라미터가 전달되며 이를 통해 access token을 발급 */

			OAuth2AccessToken oauthToken = naverLoginBO.getAccessToken(session, code, state);
			apiResult = naverLoginBO.getUserProfile(oauthToken);
//			System.out.println(apiResult);

			JSONObject jsonobj = jsonparse.stringToJson(apiResult, "response");
			String sex = jsonparse.JsonToString(jsonobj, "gender");
			String snsId = jsonparse.JsonToString(jsonobj, "id");
			String name = jsonparse.JsonToString(jsonobj, "name");

			UserVO vo = new UserVO();
			vo.setUser_snsId(snsId);
			vo.setUser_name(name);

			System.out.println(name);
			try {
				vo = service.naverLogin(vo);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}


			session.setAttribute("login",vo);
			return new ModelAndView("user/loginPost", "result", vo);
		}

이 때 페이스북 로그인과 마찬가지로 서비스를 통해 DAO로 데이터베이스에 값을 넣어준다.

8 . user/loginPost.jsp , user/callback.jsp 작성

  • loginPost.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title>NaverLogin</title>

</head>
<body>
	<script>
		self.location = '${url}';
	</script>
</body>

</html>
  • callback.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>
<head>
<title>NaverLoginTest</title>
</head>
<body>
	<br>
	<div style="text-align:center">${result}</div>
</body>

</html>


JSON to String / String to JSON


9 . 네이버에서 정보를 받을때 String 타입으로 값을 받는데 이 형태가 JSON 과 같다. JSON 안에 JSON 값을 가지고 있다. 이 부분을 객체로 변환하기 위해 String 형태로 변환시킬 필요가 있었다.

  • pom.xml 에서 라이브러리 추가한다.
<!-- json simple -->
<!-- https://mvnrepository.com/artifact/com.github.jsurfer/jsurfer-jsonsimple -->
<dependency>
  <groupId>com.github.jsurfer</groupId>
  <artifactId>jsurfer-jsonsimple</artifactId>
  <version>1.4.1</version>
</dependency>

  • 스트링 타입의 json 데이터 키의 값중 json 형태인 값을 JSON 타입으로 변환하여 반환하는 메서드와 json 타입의 키 값을 스트링으로 반환하는 메서드를 정의한다.
package com.bitproject.common;

import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

public class JsonStringParse {

	public JSONObject stringToJson(String jsonStr, String key) {
		JSONParser parser = new JSONParser();
		Object obj = null;
		try {
			obj = parser.parse(jsonStr);
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		JSONObject jsonobj = (JSONObject) obj;

		JSONObject response = (JSONObject) jsonobj.get(key);
//		
//		String profile = (String)response.get("gender");
//		System.out.println(profile);
//		

		return response;
	}

	public String JsonToString(JSONObject jsonobj, String key) {
		String str = (String)jsonobj.get(key);

		return str;
	}
}