0. 네이버 개발자 설정
다음 네이버 api 사이트에서 js + html 로
https://developers.naver.com/docs/login/api/api.md
1. APIExamNaverLogin.html 과 callback.html 의 두페이지만 구현하면 끝이난다.
혹은 naverlogin.jsp 와 callback.jsp 페이지 이다.
나머지는 부수적으로 네이버에서 데이터를 가져오는 설정 값처리이며, 무엇보다 중요한것이
APIExamNaverLogin.html 에서는 다음과 같이 간단하게 자바스크르립트로 처리후 callback.html 페이지에서 데이터를 가져올수 있으나
<script type="text/javascript"> var naver_id_login = new naver_id_login("YOUR_CLIENT_ID", "YOUR_CALLBACK_URL"); var state = naver_id_login.getUniqState(); naver_id_login.setButton("white", 2,40); naver_id_login.setDomain("YOUR_SERVICE_URL"); naver_id_login.setState(state); naver_id_login.setPopup(); naver_id_login.init_naver_id_login(); </script>
js 가 아닌 자바로 구현시 다음 naver 로그인 url 값이 생략되 있기 때문에 url 생성을 해줘야 한다.
즉, 접근토크 발급 요청 api 과정이라고 보면 된다.
<a href="https://nid.naver.com/oauth2.0/authorize? response_type=code &client_id=O9St1pC9EAPKQRlsYeWN &state=state &redirect_uri=http://localhost:8081/c3t2/Naver" id="naverLogin"> Naver 로그인 </a>
따라서, 스크립트는 의미없으며 주석 처리를 해도 작동 된다. 다만 로그인 버튼 디자인 처리를 위해 .
다음과 같은 코드만 넣도된다.
naver_id_login.setButton("white", 2,40);
<div class="naverLogin" id="naver_id_login"> <a href="https://nid.naver.com/oauth2.0/authorize? response_type=code &client_id=네이버clinet_id &state=state &redirect_uri=http://localhost:8081/naver/callback" id="naverLogin"> Naver 로그인 </a> </div> <script type="text/javascript"> /* var naver_id_login = new naver_id_login("네이버clinet_id", "http://localhost:8080/naver/callback"); var state = naver_id_login.getUniqState(); naver_id_login.setButton("white", 2,40); naver_id_login.setDomain("http://localhost:8081/c3t2"); naver_id_login.setState(state); naver_id_login.setPopup(); naver_id_login.init_naver_id_login(); */ </script> </div>
1. 라이브러리
<!--네이버 로그인 라이브러리--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.12.3</version> </dependency> <!-- OAuth2.0 --> <dependency> <groupId>com.github.scribejava</groupId> <artifactId>scribejava-core</artifactId> <version>2.8.1</version> </dependency> <!-- 제이슨 파싱 --> <dependency> <groupId>com.googlecode.json-simple</groupId> <artifactId>json-simple</artifactId> <version>1.1.1</version> </dependency>
2.NaverVO
package com.korea.webtoon.util.oauth.naver; import lombok.Data; import lombok.ToString; /** 네이버 JSON 반환 처리 샘플값 { "resultcode": "00", "message": "success", "response": { "id": "11601227211", "nickname": "sample", "profile_image": "https:\/\test.jpg", "age": "20-29", "gender": "M", "email": "test1@naver.com", "name": "홍길도", "birthday": "07-28" } } */ @Data @ToString @JsonIgnoreProperties(ignoreUnknown = true) public class NaverVO { private String resultcode; private String message; private String id; private String nickname; private String profile_image; private String age; private String gender; private String email; private String name; private String birthday; }
3. NaverOAuthApi
package com.korea.webtoon.util.oauth.naver; import org.springframework.stereotype.Component; import com.github.scribejava.core.builder.api.DefaultApi20; @Component public class NaverOAuthApi extends DefaultApi20 { @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"; } }
4.NaverLoginBO
import java.io.IOException; import java.net.URLEncoder; import java.nio.charset.Charset; import java.util.UUID; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import com.github.scribejava.core.builder.ServiceBuilder; import com.github.scribejava.core.model.OAuth2AccessToken; import com.github.scribejava.core.model.OAuthRequest; import com.github.scribejava.core.model.Verb; import com.github.scribejava.core.oauth.OAuth20Service; @Component public class NaverOAuthLoginBO { /** [[ 인증 요청문을 구성하는 파라미터]] 1.client_id: 애플리케이션 등록 후 발급받은 클라이언트 아이디 2.response_type: 인증 과정에 대한 구분값, code로 값이 고정 3.redirect_uri: 네이버 로그인 인증의 결과를 전달받을 콜백 URL(URL 인코딩) 애플리케이션을 등록할 때 Callback URL에 설정한 정보 4.state: 애플리케이션이 생성한 상태 토큰 */ private final static String CLIENT_ID = "클라이언트 아이디"; // 클라이언트 아이디 private final static String CLIENT_SECRET = "클라이언트 시크릿"; // 클라이언트 시크릿 // private final static String REDIRECT_URI = "http://localhost:8080/naver/naverRedirect"; private final static String SESSION_STATE = "oauth_state"; /** 프로필 조회 API URL */ private final static String PROFILE_API_URL = "https://openapi.naver.com/v1/nid/me"; private final static String NAVER_REDIRECT = "/naver/naverRedirect"; @Autowired private NaverOAuthApi naverOAuthApi; @Autowired private HttpServletRequest request; /** 네이버 아이디로 인증 URL 생성 Method */ public String getAuthorizationUrl(HttpSession session) { /* 세션 유효성 검증을 위하여 난수를 생성 */ String state = UUID.randomUUID().toString(); /* 생성한 난수 값을 session에 저장 */ session.setAttribute(SESSION_STATE, state); String DOMAIN = request.getScheme()+"://"+ request.getServerName() +":"+ request.getServerPort()+request.getContextPath(); String REDIRECT_URI=DOMAIN+NAVER_REDIRECT; // REDIRECT_URI= URLEncoder.encode(REDIRECT_URI, Charset.forName("UTF-8")); /* Scribe에서 제공하는 인증 URL 생성 기능을 이용하여 네아로 인증 URL 생성 */ OAuth20Service oauthService = new ServiceBuilder().apiKey(CLIENT_ID).apiSecret(CLIENT_SECRET) .callback(REDIRECT_URI).state(state) // 앞서 생성한 난수값을 인증 URL생성시 사용함 .build(naverOAuthApi); return oauthService.getAuthorizationUrl(); } /** 네이버아이디로 Callback 처리 및 AccessToken 획득 Method */ public OAuth2AccessToken getAccessToken(HttpSession session, String code, String state) throws IOException { String DOMAIN = request.getScheme()+"://"+ request.getServerName() +":"+ request.getServerPort()+request.getContextPath(); String REDIRECT_URI=DOMAIN+NAVER_REDIRECT; // REDIRECT_URI= URLEncoder.encode(REDIRECT_URI, Charset.forName("UTF-8")); /* Callback으로 전달받은 세선검증용 난수값과 세션에 저장되어있는 값이 일치하는지 확인 */ String sessionState = (String) session.getAttribute(SESSION_STATE); if (StringUtils.pathEquals(sessionState, state)) { OAuth20Service oauthService = new ServiceBuilder().apiKey(CLIENT_ID).apiSecret(CLIENT_SECRET) .callback(REDIRECT_URI).state(state).build(naverOAuthApi); /* Scribe에서 제공하는 AccessToken 획득 기능으로 네아로 Access Token을 획득 */ return oauthService.getAccessToken(code); } return null; } /** Access Token을 이용하여 네이버 사용자 프로필 API를 호출 */ public String getUserProfile(OAuth2AccessToken oauthToken) throws IOException { String DOMAIN = request.getScheme()+"://"+ request.getServerName() +":"+ request.getServerPort()+request.getContextPath(); String REDIRECT_URI=DOMAIN+NAVER_REDIRECT; // REDIRECT_URI= URLEncoder.encode(REDIRECT_URI, Charset.forName("UTF-8")); OAuth20Service oauthService = new ServiceBuilder().apiKey(CLIENT_ID).apiSecret(CLIENT_SECRET) .callback(REDIRECT_URI).build(naverOAuthApi); OAuthRequest request = new OAuthRequest(Verb.GET, PROFILE_API_URL, oauthService); oauthService.signRequest(oauthToken, request); return request.send().getBody(); } }
5.NaverController
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.github.scribejava.core.model.OAuth2AccessToken; import NaverOAuthLoginBO; import NaverVO; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @Slf4j @Controller @RequiredArgsConstructor @RequestMapping("/naver/") public class NaverOAuthController { private final NaverOAuthLoginBO naverLoginBO; /** urlNaver * * */ @GetMapping("urlNaver") @ResponseBody public String login(Model model, HttpSession session) throws Exception { /* 네아로 인증 URL을 생성하기 위하여 naverLoginBO클래스의 getAuthorizationUrl메소드 호출 */ String naverAuthUrl = naverLoginBO.getAuthorizationUrl(session); /* 생성한 인증 URL을 View로 전달 */ return naverAuthUrl; } /** 네이버 로그인 성공시 callback호출 메소드 */ @GetMapping("/naverRedirect") public String callbackNaver(Model model, @RequestParam String code, @RequestParam String state, HttpServletRequest rqeust) throws Exception { OAuth2AccessToken oauthToken; oauthToken = naverLoginBO.getAccessToken(rqeust.getSession(), code, state); // 로그인 사용자 정보를 읽어온다. String apiResult = naverLoginBO.getUserProfile(oauthToken); log.info("1.로그인 사용자 정보를 읽어온다 {}",apiResult ); JSONParser jsonParser = new JSONParser(); JSONObject jsonObj=(JSONObject) jsonParser.parse(apiResult); JSONObject responseObj = (JSONObject) jsonObj.get("response"); // objectMapper 로 json NaverVO 객체 매핑 처리리 ObjectMapper mapper=new ObjectMapper(); NaverVO naverVO = mapper.readValue(responseObj.toJSONString(), new TypeReference<NaverVO>() {}); naverVO.setResultcode(jsonObj.get("resultcode").toString()); naverVO.setMessage(jsonObj.get("message").toString()); log.info("2.로그인 사용자 정보를 읽어온다 1 {}",naverVO.toString() ); // 세션에 사용자 정보 등록 rqeust.getSession().setAttribute("naverVO", naverVO); /* 네이버 로그인 성공 페이지 View 호출 */ return "redirect:/"; } }
다음과 같이 ajax 로 urlNaver 값을 가져오는 것이 좋다.
/** urlNaver * * */ @GetMapping("urlNaver") @ResponseBody public String login(Model model, HttpSession session) throws Exception { /* 네아로 인증 URL을 생성하기 위하여 naverLoginBO클래스의 getAuthorizationUrl메소드 호출 */ String naverAuthUrl = naverLoginBO.getAuthorizationUrl(session); /* 생성한 인증 URL을 View로 전달 */ return naverAuthUrl; }
$(function(){ $("#modal_btn_login_submit").on("click", function(e){ const HOME=$("#HOME").val(); const member_id=$("#modal_login_id").val(); const member_passwd=$("#modal_login_passwd").val(); const rememberId=$("#modal_login_rememberId").is(":checked"); console.log(" 로그인 파라미터 : ", member_id, member_passwd , rememberId); if(!member_id){ alert("아이디를 입력해 주세요."); $("#id").focus(); return; } if(!member_passwd){ alert("비밀번호를 입력해 주세요."); $("#member_passwd").focus(); return; } $.ajax({ type : "POST", data : { member_id, member_passwd, rememberId }, url : `${HOME}/login/LoginPro`, success : function(res) { console.log("성공 :", res); if(res=="admin_login"){ location.href=`${HOME}/admin/admin_login`; return; } if(res.status=="failed"){ alert(res.msg); return; }else if(res.status=="success"){ //alert("로그인 성공"); location.href=`${HOME}/`; } }, error:function(res){ console.log("실패 :", res); } }); }); getNaverUrl(); }); //https://nid.naver.com/oauth2.0/authorize //?response_type=code&client_id=esfsefse52324234 //&redirect_uri=http://localhost:8080/naver/naverRedirect&state=fsdfsdewwww function getNaverUrl(){ const HOME=$("#HOME").val(); $.ajax({ type : "GET", url : `${HOME}/naver/urlNaver`, success : function(res) { console.log("urlNaver :" ,res); $("#naverLogin").attr("href", res); }, error:function(res){ console.log("실패 :", res); } }); }
6.login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>로그인</title> <style type="text/css"> #container{width:500px} .sns_join a.naver{border-color:#2db400} .sns_join a{display:block;margin-top:10px;width:100%;height:50px;border:1px solid #000;font-size:15px;line-height:50px;text-align:center;background:#fff} .sns_join a.naver>.icon{background:url(https://cdn.jsdelivr.net/gh/braverokmc79/ouath2-img@v1.0.0/images/icon_naver.png) no-repeat 0 0;background-size:18px auto} .sns_join a>.icon{display:inline-block;margin:0 auto;padding-left:29px;width:188px;color:#666;font-size:15px;letter-spacing:-1px;line-height:20px;text-align:left} </style> </head> <body> <div id="container"> <div class="sns_join"> <a class="naver" href="${urlNaver}" id="naver_id_login_anchor"> <span class="icon">네이버로 로그인</span> </a> </div> </div> </body> </html>
7.loginSuccess.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <div> <h1>환영합니다!</h1> <p> <span>${naverVO.name}</span>님의 로그인 성공<br> 이메일 주소는 <strong>${naverVO.email}</strong>입니다. </p> </div> <div> <a href="/">홈</a> </div> </body> </html>
DB 저장 mybais
<insert id="saveOauthNaver"> MERGE INTO WEBTOON_USER USING DUAL ON (EMAIL = #{email} ) WHEN MATCHED THEN UPDATE SET OAUTH = #{oauth} WHEN NOT MATCHED THEN INSERT (USER_IDX, NAME, ID, EMAIL, OAUTH) VALUES( seq_user_idx.nextVal, #{name}, #{id}, #{email}, #{oauth} ) </insert>
참조 : https://cobook.tistory.com/31
[Spring] 네이버 로그인 Open API
스프링 구글로그인 처리, Sns Google 로그인 연동
댓글 ( 4)
댓글 남기기