프로젝트/Profee

[SpringBoot] Naver 소셜 로그인 구현: OAuth2.0 & Spring Security 활용

승요나라 2024. 9. 11. 16:54

이어서 빠르게 Naver 소셜 로그인을 구현하려고 한다.

Naver 소셜 로그인도 동일하게 Google 때 구현해놓았던 틀을 기반으로 아주 간단하게 추가하므로 기반 코드가 없다면 아래 포스팅을 참고하면 좋겠다.

 

[SpringBoot] Google 소셜 로그인 구현: OAuth2.0 & Spring Security 활용

코드 구현에 앞서, 소셜 로그인 개념은 아래 포스팅을 참고하면 좋겠다. Spring Security & OAuth2.0 & JWT Token 소셜로그인 개념 정리Spring Security 란?Spring Security는 애플리케이션의 보안을 담당하는 프레

seung-yo.tistory.com

 

 

 

 

 

폴더 구조

동일하게 이전 포스팅을 따라 틀을 갖춰 놓았다면 따로 추가할 필요가 없다. NaverOauth.java, application.properties 파일만 수정할 예정이다.

 

 

 

 

 

소셜 로그인 요청 Redirect 처리 (Naver)

- NaverOauth 클래스 수정

NaverOauth.java

package com.example.Profee.service.social;

import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

// 공통 interface를 구현할 소셜 로그인 각 타입별 Class 생성 (Naver)
@Component
@RequiredArgsConstructor
public class NaverOauth implements SocialOauth {
    @Value("${sns.naver.url}")
    private String NAVER_SNS_BASE_URL;
    @Value("${sns.naver.client.id}")
    private String NAVER_SNS_CLIENT_ID;
    @Value("${sns.naver.callback.url}")
    private String NAVER_SNS_CALLBACK_URL;
    @Value("${sns.naver.client.secret}")
    private String NAVER_SNS_CLIENT_SECRET;
    @Value("${sns.naver.token.url}")
    private String NAVER_SNS_TOKEN_BASE_URL;

    @Override
    public String getOauthRedirectURL() {
        Map<String, Object> params = new HashMap<>();
        params.put("response_type", "code");
        params.put("client_id", NAVER_SNS_CLIENT_ID);
        params.put("redirect_uri", NAVER_SNS_CALLBACK_URL);
        params.put("state", "random_state_string"); // CSRF 방지를 위한 state 값 추가

        String parameterString = params.entrySet().stream()
                .map(x -> x.getKey() + "=" + x.getValue())
                .collect(Collectors.joining("&"));

        return NAVER_SNS_BASE_URL + "?" + parameterString;
    }

    @Override
    public String requestAccessToken(String code) {
        RestTemplate restTemplate = new RestTemplate();

        Map<String, Object> params = new HashMap<>();
        params.put("code", code);
        params.put("client_id", NAVER_SNS_CLIENT_ID);
        params.put("client_secret", NAVER_SNS_CLIENT_SECRET);
        params.put("redirect_uri", NAVER_SNS_CALLBACK_URL);
        params.put("grant_type", "authorization_code");
        params.put("state", "random_state_string"); // 앞서 전송한 state 값과 일치해야 함

        ResponseEntity<String> responseEntity =
                restTemplate.postForEntity(NAVER_SNS_TOKEN_BASE_URL, params, String.class);

        if (responseEntity.getStatusCode() == HttpStatus.OK) {
            // 콘솔에 받은 토큰 출력
            String tokenResponse = responseEntity.getBody();
            System.out.println("Received Access Token: " + tokenResponse);

            return responseEntity.getBody();
        }
        return "네이버 로그인 요청 처리 실패";
    }

    public String requestAccessTokenUsingURL(String code) {
        try {
            URL url = new URL(NAVER_SNS_TOKEN_BASE_URL);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            conn.setDoOutput(true);

            Map<String, Object> params = new HashMap<>();
            params.put("code", code);
            params.put("client_id", NAVER_SNS_CLIENT_ID);
            params.put("client_secret", NAVER_SNS_CLIENT_SECRET);
            params.put("redirect_uri", NAVER_SNS_CALLBACK_URL);
            params.put("grant_type", "authorization_code");
            params.put("state", "random_state_string");

            String parameterString = params.entrySet().stream()
                    .map(x -> x.getKey() + "=" + x.getValue())
                    .collect(Collectors.joining("&"));

            BufferedOutputStream bous = new BufferedOutputStream(conn.getOutputStream());
            bous.write(parameterString.getBytes());
            bous.flush();
            bous.close();

            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));

            StringBuilder sb = new StringBuilder();
            String line;

            while ((line = br.readLine()) != null) {
                sb.append(line);
            }

            if (conn.getResponseCode() == 200) {
                // 콘솔에 받은 토큰 출력
                String tokenResponse = sb.toString();
                System.out.println("Received Access Token: " + tokenResponse);

                return tokenResponse;
            }
            return "네이버 로그인 요청 처리 실패";
        } catch (IOException e) {
            throw new IllegalArgumentException("알 수 없는 네이버 로그인 Access Token 요청 URL 입니다 :: " + NAVER_SNS_TOKEN_BASE_URL);
        }
    }
}

 

 

 

 

 

 

 

application.properties 파일 설정

동일하게 Naver를 통해 발급받은 클라이언트 아이디와 시크릿을 입력해주면 된다.

 

 

application.properties

# Google
sns.google.url=https://accounts.google.com/o/oauth2/v2/auth
sns.google.client.id=구글 클라이언트 아이디
sns.google.client.secret=구글 클라이언트 시크릿
sns.google.callback.url=http://localhost:8080/auth/google/callback
sns.google.token.url=https://oauth2.googleapis.com/token

# Kakao
sns.kakao.url=https://kauth.kakao.com/oauth/authorize
sns.kakao.client.id=카카오 클라이언트 아이디
sns.kakao.client.secret=카카오 클라이언트 시크릿
sns.kakao.callback.url=http://localhost:8080/auth/kakao/callback
sns.kakao.token.url=https://kauth.kakao.com/oauth/token

# Naver
sns.naver.url=https://nid.naver.com/oauth2.0/authorize
sns.naver.client.id=네이버 클라이언트 아이디
sns.naver.client.secret=네이버 클라이언트 시크릿
sns.naver.callback.url=http://localhost:8080/auth/naver/callback
sns.naver.token.url=https://nid.naver.com/oauth2.0/token

 

 

 

 

 

이후 Spring Boot 서버를 구동시킨 다음 http://localhost:8080/auth/naver 로 들어가면 네이버 소셜 로그인이 잘 되는것을 확인할 수 있다. 😉

 

콘솔 화면

 

네이버 소셜 로그인 구현 완료