참고사이트
https://cobook.tistory.com/31
https://m.blog.naver.com/sam_sist/220969407741
새벽에 따라치고 분석하고 하느라 정신이 몽롱하다...
자고 일어나서 까먹기 전에 한 자라도 적어본다.
로그인 화면 경로로 get요청이 가면 이케저케해서 네이버 소셜 로그인 경로를 controller에서 받아와서 model인 urlNaver에 담는다.
jsp에서 링크 경로를 ${urlNaver}로 하면 버튼을 클릭했을 때
네이버의 창이 뜬다(처음에 urlNaver의 의미를 이해 못했었다.)
scribejava-core 라이브러리라는 것을 사용한다.
scribe에서 제공하는 인증 url 생성 기능이라는 것을 이용한다고 한다.
또한 accessToken 획득 기능을 제공해서 이것으로 네이버 아이디로 Access Token을 획득할 수 있다고 한다.
세션 유효성 검증을 위한 난수 생성 부분이 잘 이해가 안 갔다.
저런 식인가보다 하긴 했는데 세션 검증용 난수값과 세션에
저장되어 있는 값이 일치하는 지 확인하는 것이라는 데 어렵다. ㅜㅜ
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
<dependency>
<groupId>com.github.scribejava</groupId>
<artifactId>scribejava-core</artifactId>
<version>2.8.1</version>
</dependency>
해보지는 않았지만 아래 사이트에서 보니 여러 계정으로 테스트를 하려면 테스트 계정을 등록해야 에러가 나지 않는다.
jsp 화면에서 꼭 아래 네이버 관련 태그를 추가해야 한다.
<script type="text/javascript" src="https://static.nid.naver.com/js/naverLogin_implicit-1.0.3.js" charset="utf-8"></script>
복붙한 코드지만 백업용으로 올려본다.
package com.fastcampus.ch4.domain;
import com.github.scribejava.core.builder.api.DefaultApi20;
public class NaverOAuthApi extends DefaultApi20 {
protected NaverOAuthApi() {}
public static class InstanceHolder {
private static final NaverOAuthApi INSTANCE = new NaverOAuthApi();
}
public static NaverOAuthApi instance() {
return InstanceHolder.INSTANCE;
}
@Override
public String getAccessTokenEndpoint() {
return "https://nid.naver.com/oauth2.0/token?grant_type=authorization_code";
}
@Override
public String getAuthorizationBaseUrl() {
return "https://nid.naver.com/oauth2.0/authorize";
}
}
package com.fastcampus.ch4.domain;
import javax.servlet.http.HttpSession;
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.Response;
import com.github.scribejava.core.model.Verb;
import com.github.scribejava.core.oauth.OAuth20Service;
import org.springframework.util.StringUtils;
import java.io.IOException;
import java.util.UUID;
public class NaverLoginBo {
private static final String CLIENT_ID = "클라이언트 아이디 적으면 된다.";
private static final String CLIENT_SECRET = "클라이언트 시크릿 적으면 된다.";
private static final String REDIRECT_URI = "http://localhost:8080/login/oauth2/code/naver";
private static final String SESSION_STATE = "oauth_state";
private static final String PROFILE_API_URL = "https://openapi.naver.com/v1/nid/me";
public String getAuthorizationUrl(HttpSession session) {
String state = generateRandomString();
setSession(session, state);
OAuth20Service oauthService = new ServiceBuilder()
.apiKey(CLIENT_ID)
.apiSecret(CLIENT_SECRET)
.callback(REDIRECT_URI)
.state(state)
.build(NaverOAuthApi.instance());
return oauthService.getAuthorizationUrl();
}
public OAuth2AccessToken getAccessToken(HttpSession session, String code, String state) throws Exception {
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(NaverOAuthApi.instance());
OAuth2AccessToken accessToken = oauthService.getAccessToken(code);
return accessToken;
}
return null;
}
private String generateRandomString() {
return UUID.randomUUID().toString();
}
private void setSession(HttpSession session, String state) {
session.setAttribute(SESSION_STATE, state);
}
private String getSession(HttpSession session) {
return (String)session.getAttribute(SESSION_STATE);
}
public String getUserProfile (OAuth2AccessToken oauthToken) throws Exception {
OAuth20Service oauthService = new ServiceBuilder()
.apiKey(CLIENT_ID)
.apiSecret(CLIENT_SECRET)
.callback(REDIRECT_URI).build(NaverOAuthApi.instance());
OAuthRequest request = new OAuthRequest(Verb.GET, PROFILE_API_URL, oauthService);
oauthService.signRequest(oauthToken, request);
Response response = request.send();
return response.getBody();
}
}
package com.fastcampus.ch4.controller;
import com.fastcampus.ch4.domain.NaverLoginBo;
import com.github.scribejava.core.model.OAuth2AccessToken;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
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.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpSession;
@Controller
public class CityTurtleController {
private NaverLoginBo naverLoginBo;
private String apiResult = null;
@Autowired
private void setNaverLoginBo(NaverLoginBo naverLoginBo) {
this.naverLoginBo = naverLoginBo;
}
@RequestMapping(value = "/login.do", method = {RequestMethod.GET, RequestMethod.POST})
public String login(Model model, HttpSession session) {
String naverAuthUrl = naverLoginBo.getAuthorizationUrl(session);
System.out.println("네이버~~:: " + naverAuthUrl);
model.addAttribute("urlNaver", naverAuthUrl);
return "login";
}
//네이버 로그인 성공시 콜백
@RequestMapping(value = "/login/oauth2/code/naver", method = {RequestMethod.GET, RequestMethod.POST})
public String callbackNaver(Model model, @RequestParam String code, @RequestParam String state, HttpSession session) throws Exception {
System.out.println("시스템 성공 콜백 ");
OAuth2AccessToken oauthToken;
oauthToken = naverLoginBo.getAccessToken(session, code, state);
apiResult = naverLoginBo.getUserProfile(oauthToken);
JSONParser jsonParser = new JSONParser();
JSONObject jsonObj;
jsonObj = (JSONObject) jsonParser.parse(apiResult);
JSONObject response_obj = (JSONObject) jsonObj.get("response");
String email = (String) response_obj.get("email");
String name = (String) response_obj.get("name");
session.setAttribute("signin", apiResult);
session.setAttribute("email", email);
session.setAttribute("name", name);
return "redirect:/loginSuccess.do";
}
@RequestMapping("/loginSuccess.do")
public String loginSuccess() {
return "loginSuccess";
}
}