*Spring Framework를 사용한 기능 구현
*kakao login 진행 흐름에 따라 작성 하였으며, 내용이 길어지는 것을 방지하기 위해
MemberService와 MemberMapper 를 생략하였음을 알려드립니다.
naver login
pom.xml
- dependency를 추가한다.
<dependency>
<groupId>com.github.scribejava</groupId>
<artifactId>scribejava-core</artifactId>
<version>2.8.1</version>
</dependency>
NaverLoginApi.java
package com.finalproject.petkage.member.model.service;
import org.springframework.stereotype.Component;
import com.github.scribejava.core.builder.api.DefaultApi20;
@Component
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";
}
}
NaverLoginBO.java
package com.finalproject.petkage.member.model.vo;
import java.io.IOException;
import java.util.UUID;
import javax.servlet.http.HttpSession;
import org.springframework.util.StringUtils;
import com.finalproject.petkage.member.model.service.NaverLoginApi;
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;
public class NaverLoginBO {
/* 인증 요청문을 구성하는 파라미터 */
//client_id: 애플리케이션 등록 후 발급받은 클라이언트 아이디
//response_type: 인증 과정에 대한 구분값. code로 값이 고정돼 있습니다.
//redirect_uri: 네이버 로그인 인증의 결과를 전달받을 콜백 URL(URL 인코딩). 애플리케이션을 등록할 때 Callback URL에 설정한 정보입니다.
//state: 애플리케이션이 생성한 상태 토큰
private final static String CLIENT_ID = "Client ID";
private final static String CLIENT_SECRET = "Client Secret";
private final static String REDIRECT_URI = "http://localhost:8083/petkage/member/callbackNaver";
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) //앞서 생성한 난수값을 인증 URL생성시 사용함
.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();
}
}
- REDIRECT_URI에는 네이버 개발자센터에 등록했던 Callback URL를 입력한다.
- 위 과정을 통해 네이버 API 사용 인증을 가져오며 네이버 계정에 따라 회원 프로필 정보를 얻어온다.
- API Key를 입력하는 부분은 보안을 위해 properties 파일로 개별 관리 해도 되지만 우선 직접 처리하도록 구성했다.
MemberController.java
/* NAVER */
// NaverLoginBO
private NaverLoginBO naverLoginBO;
private String apiResult = null;
@Autowired
private void setNaverLoginBO(NaverLoginBO naverLoginBO) {
this.naverLoginBO = naverLoginBO;
}
- controller 상단에 추가한다.
MemberController("/loginPage").java
public String loginPage(Model model,HttpSession session) {
log.info("로그인 페이지 요청");
/* 네이버아이디로 인증 URL을 생성하기 위하여 naverLoginBO클래스의 getAuthorizationUrl메소드 호출 */
String naverAuthUrl = naverLoginBO.getAuthorizationUrl(session);
System.out.println("네이버: " + naverAuthUrl);
//네이버
model.addAttribute("url", naverAuthUrl);
return "member/login";
}
- 네이버 로그인 버튼이 있는 로그인 페이지를 요청할 때 미리 만들어 놓은 NaverloginBO에서 session을 불러와 변수에 저장한다.
- 위 값은 model을 통해 네이버 로그인 페이지로 넘어가도록 설정한다.
login.jsp
<button type="button" class="btn btn-block" id="naver_id_login" onclick="location.href='${url}'">
네이버로 로그인
</button>
- 네이버 로그인 버튼을 클릭하면 넘겨 받은 url 주소로 넘어가 네이버 로그인 창이 열린다.
- 테스트 ID로 등록된 계정으로 로그인 하면 네이버 개발자센터에서 사전 등록한 넘겨 받을 개인 정보 관련 동의 항목이 열린다.