본문 바로가기

개발리뷰

OAuth 2.0 네이버 로그인 개발 리뷰

안녕하세요! J입니다. 이번에는 제가 참여한 프로젝트에서 제가 맡은 부분 중 하나인 OAuth 2.0을 이용한 네이버 로그인을 리뷰해보도록 하겠습니다. Java Spring boot로 진행하였습니다. 

 

OAuth란? (개념설명)

오해했던 점: 로그인을 대신 해주는 기술이 아니다.

 

등장인물 소개

유저(리소스 소유자)

자신을 인증하여 서비스를 이용하고자하는 주체입니다. 로그인 정보인 아이디와 비밀번호를 제공합니다.

 

리소스 서버(리소스 제공자)

로그인에 성공할 경우, 해당 사용자의 리소스(정보)를 클라이언트에게 전달합니다.

 

내 서비스 서버(클라이언트)

제공자로부터 받은 사용자의 정보를 활용하여 사용자 인증을 진행하고 JWT를 발급합니다.

 

과정

1. 사용자가 저희 서비스에 접근합니다. 저희 서비스는 사용자로부터 인증을 요구하죠. 그럼 인증을 위해 로그인 페이지를 응답합니다. 사용자는 여기에서 소셜 로그인 제공자를 선택하죠. 

 

2. 사용자는 소셜 로그인 화면에서 자신의 로그인정보를 제공자에게 제공합니다. 사용자의 정보제공에 대한 동의를 받습니다. 이 단계에서 저희 서비스를 통하는 것뿐이지 저희 서비스에 정보를 제공하지 않고, 리소스 서버에 정보를 제공한다는 점은 주목할만합니다. 굳이 같은 사용자의 다른 서비스에 대한 로그인 정보를 저희가 가져서 보안을 고려할 필요가 없기 때문이죠. 사용자 또한 안심할 수 있겠습니다. 

 

3. 정상적인 로그인 정보가 제공된 경우, 제공자는 클라이언트에게 미리 설정된 URL인 Callback Url로 어떤 토큰을 하나 보냅니다. 클라이언트는 이 토큰을 활용해서 제공자로부터 로그인을 요청한 사용자의 정보를 동의된 내용에 한하여 받아올 수 있습니다. 인증을 요청한 사용자에 대한 정보를 제공받기만 할 뿐, 로그인이 된 것이 아닙니다.

 

4. 받아온 정보를 개발하는 서비스에 맞게 조절하는 과정에 활용하는 과정을 거치게 됩니다. 저희는 JWT를 발급하는 과정으로 논의하였습니다. 

 

 

네이버에 서비스(프로젝트, 어플리케이션) 등록하기

먼저, 네이버 개발자 페이지로 갑니다.

https://developers.naver.com/apps/#/register

등록하는 과정은 추후에 상세히 업데이트하도록 하겠습니다.

이 과정에서 필수적인 것은 다음과 같습니다. 

아래와 같이 네이버에 등록된 나의 프로젝트(클라이언트)의 ID와 PW가 필요합니다. 

마지막으로, 다음 과정에서 필요한 Callback URL이 필요합니다.

배포 전에 함께 개발하는 동료들의 계정이나 테스트용 계정을 추가하고 싶다면, 멤버 관리 탭에 들어가서 추가해주세요.

이 과정을 생략하면 클라이언트를 등록한 네이버 계정의 데이터만 네이버(리소스 제공자)로부터 받을 수 있습니다. 

 

의존성 추가하기 및 서비스 구성

OAuth 2.0을 사용하기 위해 필요한 의존성을 추가해줍니다. 

// OAuth2
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'

 

다음으로 저희 어플리케이션(클라이언트)에 네이버(리소스 제공자)에 대한 설정을 해주도록 합니다. 

spring:
  security:
    oauth2:
      client:
        provider:
          naver:
            authorization-uri: https://nid.naver.com/oauth2.0/authorize
            token-uri: https://nid.naver.com/oauth2.0/token
            user-info-uri: https://openapi.naver.com/v1/nid/me
            user-name-attribute: response
        registration:
          naver:
            client-id: ${NAVER_ID}
            client-secret: ${NAVER_SECRET}
            redirect-uri: http://ec2-43-200-130-95.ap-northeast-2.compute.amazonaws.com:8080/login/oauth2/code/naver
            authorization-grant-type: authorization_code
            client-authentication-method: client_secret_post
            client-name: Naver
            scope:
              - nickname
              - email

 

registration - naver - client-id 와 client-secret에 저희는 현재 환경변수로 데이터를 넣었습니다.

 

★위의 내용이 노출되지 않도록 꼭 조치해주세요. 보안사고의 위험이 큽니다!★

 

네이버에 서비스를 등록한 후에 얻은 ID와 Secret이 여기에 들어갑니다. 

그 다음 줄의 redirect-uri에 등록할 때 작성한 Callback url을 동일하게 작성합니다. 

 

OAuth2UserServiceImpl

이 클래스는 DefaultOAuth2UserService를 상속받는 클래스로, 사용자가 정상적으로 네이버 로그인을 통해 인증하면 사용자의 데이터를 조회하고 처리하는 클래스입니다. loadUser 메서드를 다음과 같이 구현하였습니다. 

@Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
        OAuth2User oAuth2User = super.loadUser(userRequest);
        String registrationId = userRequest
                .getClientRegistration()
                .getRegistrationId(); // 제공자 정보 naver, google, kakao, ...
                
        String nameAttribute = "";
        
        Map<String, Object> attributes = new HashMap<>(); // 사용할 데이터를 가공해서 담을 Map

        // naver 로직
        if (registrationId.equals("naver")) {
            attributes.put("provider", "naver");

            // 받은 사용자 데이터를 정리
            Map<String, Object> responseMap = oAuth2User.getAttribute("response");
            attributes.put("id", responseMap.get("id"));
            attributes.put("email", responseMap.get("email"));
            attributes.put("nickname", responseMap.get("nickname"));
            nameAttribute = "email";
        }

        log.info(attributes.toString());
        // 기본설정으로는 여기까지 오면 인증 성공
        return new DefaultOAuth2User(
                Collections.singleton(new SimpleGrantedAuthority("USER")),
                attributes,
                nameAttribute
        );

 

OAuth2SuccessHandler

다음은 사용자의 데이터를 성공적으로 받아온 후 동작할 OAuth2SuccessHandler 클래스를 정의합니다. 저희 팀의 프로젝트는 JWT 토큰 방식으로 인증을 하기로 논의되었기 때문에, JWT를 생성하도록 정의하였습니다. 클라이언트에게 JWT를 제공하고, 토큰의 정보를 그대로 반환하는 엔드포인트로 Redirect 하는 과정을 간소화 하기 위해서 SimpleUrlAuthenticationSuccessHandler를 상속받아 사용하였습니다.

@Override
    // 인증 성공시 호출되는 메소드
    public void onAuthenticationSuccess(
            HttpServletRequest request,
            HttpServletResponse response,
            Authentication authentication
    ) throws IOException, ServletException {

		// OAuth2UserServiceImpl에서 반환한 DefaultOAuth2User가 저장된다.
        OAuth2User oAuth2User
                = (OAuth2User) authentication.getPrincipal();
        // 소셜 로그인을 한 새로운 사용자를 우리의 UserEntity로 전환하기 위한 작업
        // username: Email을 @ 기준으로 나누고,
        // ID Provider(Naver) 같은 값을 추가하여 조치
        String email = oAuth2User.getAttribute("email");
        String provider = oAuth2User.getAttribute("provider");
        String username = email;
        String providerId = oAuth2User.getAttribute("id").toString();
        Optional<User> optionalUser = userRepository.findByUsername(username);
        // 처음으로 소셜 로그인한 사용자를 데이터베이스에 등록
        if (optionalUser.isEmpty()) {
            User user = new User(username, providerId,null,null, Role.USER);
            userRepository.save(user);
        }

        // 데이터베이스에서 사용자 회수
        User user = userRepository.findByUsername(username).get();

        // JWT 생성
//        String jwt = tokenUtils
//                .generateToken(User
//                        .withUsername(oAuth2User.getName())
//                        .password(oAuth2User.getAttribute("id").toString())
//                        .build());

        String jwt = tokenProvider.createAccessToken(user);
        log.info(jwt);

        // 목적지 URL 설정
        // 우리 서비스의 Frontend 구성에 따라 유연하게 대처해야 한다.
        String targetUrl = String.format(
                "http://localhost:8080/api/val?token=%s", jwt
        );
        // 실제 Redirect 응답 생성
        getRedirectStrategy().sendRedirect(request, response, targetUrl);
    }

 

이상으로 OAuth2.0 네이버 로그인 구현 리뷰를 마칩니다. 

'개발리뷰' 카테고리의 다른 글

[MyBatis] N개의 INSERT -> 1개의 INSERT  (0) 2025.07.08
RISS 국내 논문 데이터 크롤링 프로젝트  (0) 2023.10.12
MySql 사용하기  (0) 2023.10.10