슬기로운 개발생활

Spring Boot 게시판 OAuth 2.0 네이버 로그인 구현

by coco3o
반응형

이전 게시글에 이어서 네이버 OAuth 2.0 로그인을 구현하도록 하자.

Spring Boot 게시판 OAuth 2 구글 로그인 구현

Spring Boot에 Spring Security와 OAuth2.0을 사용해 소셜 로그인을 구현해보도록 하자. 1. 구글 OAuth 서비스 등록 필자는 이미 만들어놓은 프로젝트가 있어 예시 프로젝트를 하나 생성해보도록 하겠다. 1-1.

dev-coco.tistory.com


1. 네이버 OAuth 서비스 등록

필자는 이미 만들어놓은 프로젝트가 있어 예시 프로젝트를 하나 생성해보도록 하겠다.

1-1. 네이버 OAuth 서비스를 등록하기 위해 다음 링크를 통해 네이버 개발자 센터로 이동한다.
https://developers.naver.com/main/

NAVER Developers

네이버 오픈 API들을 활용해 개발자들이 다양한 애플리케이션을 개발할 수 있도록 API 가이드와 SDK를 제공합니다. 제공중인 오픈 API에는 네이버 로그인, 검색, 단축URL, 캡차를 비롯 기계번역, 음

developers.naver.com

1-2. 애플리케이션 등록 > 애플리케이션 이름 입력 > 사용 API 선택 (네이버 로그인) > 제공 정보 선택

1-3. 환경 추가 (PC 웹) > 서비스 URL 입력(http://localhost:8080) > 네이버 아이디로 로그인 입력(http://localhost:8080/login/oauth2/naver) > 등록하기

1-4. 클라이언트 아이디, 클라이언트 비밀번호 GET


2. application-oauth.properties

# GOOGLE
...

# Naver
spring.security.oauth2.client.registration.naver.client-id=클라이언트ID
spring.security.oauth2.client.registration.naver.client-secret=클라이언트Secret

# Naver Spring Security 수동 입력
# == http://localhost:8080/login/oauth2/code/naver
spring.security.oauth2.client.registration.naver.redirect-uri={baseUrl}/{action}/oauth2/code/{registrationId}
spring.security.oauth2.client.registration.naver.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.naver.scope=name,email,nickname
spring.security.oauth2.client.registration.naver.client-name=Naver

# provider
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
# Security의 기준이 되는 username의 이름을 네이버에서는 response로 (회원 조회시 반환되는 JSON 형태 때문)
spring.security.oauth2.client.provider.naver.user-name-attribute=response

네이버는 스프링 시큐리티를 공식 지원하지 않기 때문에 Provider를 직접 입력해줘야 한다.
자세한 가이드는 네이버 api 에 자세히 나와있으니 참고하자.


3. OAuthAttributes

@Slf4j
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Getter
public class OAuthAttributes {

    private Map<String, Object> attributes;
    private String nameAttributeKey;
    private String username;
    private String nickname;
    private String email;
    private Role role;

    public static OAuthAttributes of(String registrationId,
                                     String userNameAttributeName,
                                     Map<String, Object> attributes) {
        /* 구글인지 네이버인지 카카오인지 구분하기 위한 메소드 (ofNaver, ofKaKao) */
        if ("naver".equals(registrationId)) {
            return ofNaver("id", attributes);
        }

        return ofGoogle(userNameAttributeName, attributes);
    }

    // ofGoogle 생략
    
    private static OAuthAttributes ofNaver(String userNameAttributeName, Map<String, Object> attributes) {
        /* JSON형태이기 때문에 Map을 통해 데이터를 가져온다. */
        Map<String, Object> response = (Map<String, Object>) attributes.get("response");

        log.info("naver response : " + response);

        return OAuthAttributes.builder()
                .username((String) response.get("email"))
                .email((String) response.get("email"))
                .nickname((String) response.get("nickname"))
                .attributes(response)
                .nameAttributeKey(userNameAttributeName)
                .build();
    }
    public User toEntity() {
        return User.builder()
                .username(email)
                .email(email)
                .nickname(nickname)
                .role(Role.SOCIAL)
                .build();
    }
}

OAuth2UserService를 통해 가져온 네이버 OAuth2User의 attributes를 담는다.


4. Mustache

header.mustache

<!DOCTYPE HTML>
<html>
<head>
    <title>Board Service</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.6.0/font/bootstrap-icons.css">
    <link rel="stylesheet" href="/css/app.css">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
</head>
<body>
<div id="header"class="d-flex bd-highlight">
    <a href="/" class="p-2 flex-grow-1 bd-highlight">Board Service</a>
    <form action="/posts/search" method="GET" class="form-inline p-2 bd-highlight" role="search">
        <input type="text" name="keyword" class="form-control" id="search" placeholder="검색">
        <button class="btn btn-success bi bi-search"></button>
    </form>
</div>

<nav id ="nav">
    <div class="text-right">
        {{#user}}
            <span class="mx-3">{{user}}님 안녕하세요!</span>
            <a href="/logout" class="btn btn-outline-dark">로그아웃</a>
            <a href="/modify" class="btn btn-outline-dark bi bi-gear"></a>
        {{/user}}
        {{^user}}
            <a href="/oauth2/authorization/naver" role="button" class="btn btn-outline-success"><img id="img" src="/img/naver.ico"/> 로그인</a>
            <a href="/oauth2/authorization/google" role="button" class="btn btn-outline-danger bi bi-google"> 로그인</a>
            <a href="/auth/login" role="button" class="btn btn-outline-dark bi bi-lock-fill"> 로그인</a>
            <a href="/auth/join" role="button" class="btn btn-outline-dark bi bi-person-circle"> 회원가입</a>
        {{/user}}
    </div>
</nav>

로그인 url은 /oauth2/authorization/naver 으로 연결한다.


5. 결과 확인

5-1. 네이버 로그인 버튼 클릭
authorization_url로 이동한다.

5-2. 네이버 ID, PW 입력
아이디와 비밀번호가 일치하면 로그인 요청 코드가 담긴 콜백 url값을 보내고 그것을 oauth2.0/token이 전달받아 인증해준다.

5-3. 로그인 성공

인증이 성공하면 로그인이 완료된다.

반응형

블로그의 정보

슬기로운 개발생활

coco3o

활동하기