[Spring] 네이버 로그인 API 구현

Wonjun Seo·2023년 4월 15일
0

Spring Framework에서 네이버 아이디를 사용하여 로그인 하는 과정을 정리한 글입니다.

  • 참고 사항
    • 설정 과정 중에 틀린 부분이 많을 수도 있습니다.
    • 저는 로그인시 이름과 이메일만 필수로 설정하였습니다. 개인에 따라 필요한 정보를 알맞게 설정하세요.
    • 네이버 개발자 사이트 주소: https://developers.naver.com/main/

1. 애플리케이션 이름과 API 설정

애플리케이션 이름을 설정하고, 사용 API에서 '네이버 로그인'을 선택합니다.


2. 네이버 로그인 권한 설정

네이버 로그인시 사용자로부터 받을 정보를 설정합니다.


3. URL과 Callback URL 설정

서비스 URL과 Callback URL을 설정합니다. 서비스 URL은 네이버 아이디 서비스를 사용하려는 사이트의 기본 주소를 말합니다. 그리고, Callback URL은 로그인 완료시 정보를 받을 페이지의 주소 입니다.


4. 내 애플리케이션 정보 확인

나중에 application properties 설정할 때 사용할 정보 입니다.


프로젝트 설정

application.properties 설정

spring.security.oauth2.client.registration.naver.client-id=client-id
spring.security.oauth2.client.registration.naver.client-secret=client-secret
spring.security.oauth2.client.registration.naver.scope=name, email
spring.security.oauth2.client.registration.naver.client-name=Naver
spring.security.oauth2.client.registration.naver.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.naver.redirect-uri=http://localhost:8080/login/oauth2/code/naver

spring.security.oauth2.client.provider.naver.authorization-uri=https://nid.naver.com/oauth2.0/authorize
spring.security.oauth2.client.provider.naver.token-uri=https://nid.naver.com/oauth2.0/token
spring.security.oauth2.client.provider.naver.user-info-uri=https://openapi.naver.com/v1/nid/me
spring.security.oauth2.client.provider.naver.user-name-attribute=response

네이버 로그인 서비스를 사용하기 위해 application.properties 파일에 다음과 같은 내용을 추가합니다.


public class NaverUserInfo implements OAuth2UserInfo{

    private Map<String, Object> attributes;

    public NaverUserInfo(Map<String, Object> attributes) {
        this.attributes = attributes;
    }

    @Override
    public String getProviderId() {
        return String.valueOf(attributes.get("id"));
    }

    @Override
    public String getName() {
        return String.valueOf(attributes.get("name"));
    }

    @Override
    public String getEmail() {
        return String.valueOf(attributes.get("email"));
    }

    @Override
    public String getProvider() {
        return "naver";
    }

}

네이버 유저의 정보를 저장할 객체를 생성합니다.


PrincipalOAuth2UserService.java

@Service
public class PrincipalOAuth2UserService extends DefaultOAuth2UserService {

    @Autowired
    private MemberRepository memberRepository;

    @Autowired
    private MemberService memberService;

    // userRequest는 code를 받아서 accessToken을 응답 받은 객체
    @Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
        OAuth2User oAuth2User = super.loadUser(userRequest); // google의 회원 프로필 조회

        // code를 통해 구성한 정보
        System.out.println("userRequest clientRegistration : " + userRequest.getClientRegistration());

        // token을 통해 응답받은 회원정보
        System.out.println("oAuth2User : " + oAuth2User);

        return processOAuth2User(userRequest, oAuth2User);
    }

    private OAuth2User processOAuth2User(OAuth2UserRequest userRequest, OAuth2User oAuth2User) {
    
        OAuth2UserInfo oAuth2UserInfo = null;
        if (userRequest.getClientRegistration().getRegistrationId().equals("google")) {
            oAuth2UserInfo = new GoogleUserInfo(oAuth2User.getAttributes());
        } else if (userRequest.getClientRegistration().getRegistrationId().equals("naver")){
            oAuth2UserInfo = new NaverUserInfo((Map)oAuth2User.getAttributes().get("response"));
        } 

        Optional<Member> userOptional =
                memberRepository.findByProviderAndProviderId(oAuth2UserInfo.getProvider(), oAuth2UserInfo.getProviderId());

        Member member;
        if (userOptional.isPresent()) {
            member = userOptional.get();
            memberService.updateVisits(member.getEmail());
        } else {
            member = Member.builder()
                    .nickname(oAuth2UserInfo.getProvider() + "_" + oAuth2UserInfo.getProviderId().substring(0, 6))
                    .email(oAuth2UserInfo.getEmail())
                    .role(Role.SOCIAL)
                    .provider(oAuth2UserInfo.getProvider())
                    .providerId(oAuth2UserInfo.getProviderId())
                    .build();
            memberService.updateVisits(oAuth2UserInfo.getEmail());
            memberRepository.save(member);
        }

        return new PrincipalDetails(member, oAuth2User.getAttributes());
    }
}

네이버 로그인 요청을 처리할 클래스를 작성합니다.


Login.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorate="~{layouts/mainLayout}">

<th:block layout:fragment="css">
    <style>
        a {
            color: black;
        }
        .error {
            color: #bd2130;
        }
    </style>
</th:block>


<div layout:fragment="content">
    <form style="width: 50%; margin: 0 auto;" role="form" method="post" action="/member/login">
        <div class="form-group">
            <label th:for="email">Email</label>
            <input type="email" name="email" class="form-control">
            <small id="emailHelp" class="form-text text-muted"><p th:if="${loginErrorMsg}" class="error" th:text="${loginErrorMsg}"></p></small>
        </div>
        <div class="form-group">
            <label th:for="password">Password</label>
            <input type="password" name="password" id="password" class="form-control">
        </div>
        <div class="form-group">
            <button type="submit" class="form-control btn btn-dark">로그인</button>
        </div>
        <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
        <div class="form-group">
            <a href="/oauth2/authorization/google" class="form-control btn btn-dark">Google 로그인</a>
        </div>
        <div class="form-group">
            <a href="/oauth2/authorization/naver" class="form-control btn btn-dark">Naver 로그인</a>
        </div>
    </form>
</div>
</html>

로그인 페이지를 생성합니다. 네이버 로그인을 사용하기 위한 버튼을 생성합니다.

0개의 댓글