SW/Java

Java : Spring Boot : 네이버 아이디로 로그인 : 예제, 구현

얇은생각 2020. 8. 24. 20:00
반응형

Java : Spring Boot : 네이버 아이디로 로그인 : 예제, 구현

 

NaverController

package com.spring.reai.user.controller;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@Slf4j
@Controller
public class NaverController {

    private final static String NAVER_CLIENT_ID = "클라이언트 아이디";
    private final static String NAVER_CLIENT_SECRET = "클라이언트 시크릿";
    private final static String NAVER_REDIRECT_URI = "리다이렉트 경로";

    public String getAuthorizationUrl(HttpSession session) {
        String state = generateRandomString();

        String naverUrl = "https://nid.naver.com/oauth2.0/authorize" +
                "?client_id=" + NAVER_CLIENT_ID +
                "&response_type=code" +
                "&redirect_uri=" + NAVER_REDIRECT_URI +
                "&state=" + state;

        return naverUrl;
    }


    public String getAccessToken(String autorize_code, String state) {
        final String RequestUrl = "https://nid.naver.com/oauth2.0/token";

        final List<NameValuePair> postParams = new ArrayList<NameValuePair>();
        postParams.add(new BasicNameValuePair("client_id", NAVER_CLIENT_ID)); // REST API KEY
        postParams.add(new BasicNameValuePair("client_secret", NAVER_CLIENT_SECRET));
        postParams.add(new BasicNameValuePair("grant_type", "authorization_code"));
        postParams.add(new BasicNameValuePair("state", state));
        postParams.add(new BasicNameValuePair("code", autorize_code)); // 로그인 과정 중 얻은 code 값

        final HttpClient client = HttpClientBuilder.create().build();
        final HttpPost post = new HttpPost(RequestUrl);
        JsonNode returnNode = null;

        try {
            post.setEntity(new UrlEncodedFormEntity(postParams));
            final HttpResponse response = client.execute(post);
            final int responseCode = response.getStatusLine().getStatusCode();

            // JSON 형태 반환값 처리
            ObjectMapper mapper = new ObjectMapper();
            returnNode = mapper.readTree(response.getEntity().getContent());

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();

        } catch (ClientProtocolException e) {
            e.printStackTrace();

        } catch (IOException e) {
            e.printStackTrace();

        } finally {
            // clear resources
        }

        return returnNode.get("access_token").toString();
    }

    public JsonNode getNaverUserInfo(String autorize_code, String state) {
        final String RequestUrl = "https://openapi.naver.com/v1/nid/me";

        final HttpClient client = HttpClientBuilder.create().build();
        final HttpPost post = new HttpPost(RequestUrl);
        String accessToken = getAccessToken(autorize_code, state);

        post.addHeader("Authorization", "Bearer " + accessToken);

        JsonNode returnNode = null;

        try {
            final HttpResponse response = client.execute(post);
            final int responseCode = response.getStatusLine().getStatusCode();
            System.out.println("\nSending 'POST' request to URL : " + RequestUrl);
            System.out.println("Response Code : " + responseCode);

            // JSON 형태 반환값 처리
            ObjectMapper mapper = new ObjectMapper();
            returnNode = mapper.readTree(response.getEntity().getContent());
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();

        } catch (ClientProtocolException e) {
            e.printStackTrace();

        } catch (IOException e) {
            e.printStackTrace();

        } finally {
            // clear resources
        }

        return returnNode;
    }

    // Todo: 로그아웃시 토큰 삭제
    public String deleteNaverToken(){
        String RequestURl = "https://nid.naver.com/oauth2.0/token" +
                "?grant_type=delete" +
                "&client_id={클라이언트 아이디}" +
                "&client_secret={클라이언트 시크릿}" +
                "&access_token={접근 토큰}" +
                "&service_provider=NAVER";
        return "";
    }

    private String generateRandomString() {
        return UUID.randomUUID().toString();
    }
}

 

 

LoginController

package com.spring.reai.user.controller;

import com.fasterxml.jackson.databind.JsonNode;
import com.spring.reai.user.entity.UserInfo;
import com.spring.reai.user.repository.UserInfoRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.view.RedirectView;

import javax.servlet.http.HttpSession;
import java.util.List;

@Slf4j
@Controller
@RequestMapping("user")
public class LoginController {

    @Autowired
    NaverController naverLogin;

    @Autowired
    UserInfoRepository userInfoRepo;

    @GetMapping("login")
    public String getLoginPage(Model model, HttpSession session) {

        String kakaoUrl = kakaoLogin.getAuthorizationUrl(session);
        String naverUrl = naverLogin.getAuthorizationUrl(session);

        model.addAttribute("naver_url", naverUrl);

        return "login";
    }

    @GetMapping("logout")
    public String getLogoutPage(Model model, HttpSession session) {
        session.invalidate();

        return "redirect:/";
    }

    @RequestMapping(value = "/naverOauth")
    public RedirectView getNaverSignIn(ModelMap model,
                                       @RequestParam("code") String code,
                                       @RequestParam("state") String state,
                                       HttpSession session) throws Exception
    {
        JsonNode responseInfo = naverLogin.getNaverUserInfo(code, state);
        JsonNode userInfo = responseInfo.get("response");

        log.info(userInfo.toString());


        String id = userInfo.get("id").toString();
        String nickname = userInfo.get("nickname").toString();

        List<UserInfo> checkedUserInfo = userInfoRepo.findById(id);
        if(checkedUserInfo.size() ==  0 ){
            UserInfo userInfo1 = new UserInfo();
            userInfo1.id = id;
            userInfo1.nickname = nickname;
            userInfo1.platform = "naver";
            userInfoRepo.save(userInfo1);
        }

        session.setAttribute("nickname", nickname);

        return new RedirectView("/");
    }
}

 

네이버 아이디로 구현하는 예제가 적당한게 없어서 기록을 남기게 되었다.

기존 코드들 라이브러리 버전이 낮아서, 최근 spring boot와 호환이 되지 않아 빌드가 되지 않는 문제가 있었다.

카카오 로그인 예제도 거의 동일하게 구현이 가능하였다.

 

간단하게 요약을 하자면, 우선 네이버 로그인을 할 수 있도록 해당 url을 유저에게 제공해야 한다.

해당 url에서 로그인을 하면 액세스 토큰을 리다이렉트 경로로 POST 방식을 넘겨준다.

서버에서 해당 토큰을 가지고, 유저의 정보를 요청하여 받아 올 수 있다.

네이버에서 해당 유저의 정보를 받아서, 필요한 로직에 따라 알맞게 처리하면 된다. 

 

시간이 나면, 다시 구조를 가다듬고 리팩토링을 진행하고, 로그아웃 기능까지 마무리해야 한다.

반응형