본문 바로가기

프로젝트_ 커피주문 서비스

네이버 로그인 API (+구글 로그인 API)

  • 구글 로그인은 API 적용만 해놓고 사용하지 않음 -> 추후 소셜 로그인 시 추가정보 입력을 통해 확장할 예정
  • 각 플랫폼 API 사용법은 생략
  • application-oauth.properties
#Google Login
spring.security.oauth2.client.registration.google.clientId= !클라이언트 ID!
spring.security.oauth2.client.registration.google.clientSecret= !클라이언트 비밀번호!
spring.security.oauth2.client.registration.google.scope=profile,email

#Naver Login
spring.security.oauth2.client.registration.naver.clientId = !클라이언트 ID!
spring.security.oauth2.client.registration.naver.clientSecret = !클라이언트 비밀번호!
spring.security.oauth2.client.registration.naver.redirectUri= {baseUrl}/{action}/oauth2/code/{registrationId}
spring.security.oauth2.client.registration.naver.authorizationGrantType=authorization_code
spring.security.oauth2.client.registration.naver.scope = name,email, nickname
spring.security.oauth2.client.registration.naver.clientName=Naver
#Naver Login Provider
spring.security.oauth2.client.provider.naver.authorizationUri=https://nid.naver.com/oauth2.0/authorize
spring.security.oauth2.client.provider.naver.tokenUri=https://nid.naver.com/oauth2.0/token
spring.security.oauth2.client.provider.naver.userInfoUri=https://openapi.naver.com/v1/nid/me
spring.security.oauth2.client.provider.naver.userNameAttribute=response

 

 

  • application.properties
#Login
spring.profiles.include=oauth

spring.h2.console.enabled=true


spring.jpa.defer-datasource-initialization=true

logging.level.org.hibernate.SQL = DEBUG
spring.jpa.properties.hibernate.format_sql = true
#sql trace
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE

#unique URL ??
spring.datasource.generate-unique-name=false
#h2 DB URL
spring.datasource.url=jdbc:h2:mem:coffeedb

 

 

  • config/auth/CustomOAuth2UserService
package com.example.CoffeeShop.config.auth;

import com.example.CoffeeShop.Entity.User;
import com.example.CoffeeShop.Repository.UserRepository;
import com.example.CoffeeShop.config.auth.DTO.OAuthAttributes;
import com.example.CoffeeShop.config.auth.DTO.SessionUser;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Service;

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

@RequiredArgsConstructor
@Service
public class CustomOAuth2UserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> {
    private final UserRepository userRepository;
    private final HttpSession httpSession;

    @Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
        OAuth2UserService delegate = new DefaultOAuth2UserService();
        OAuth2User oAuth2User = delegate.loadUser(userRequest);

        String registrationId = userRequest.getClientRegistration().getRegistrationId();
        String userNameAttributeName = userRequest.getClientRegistration().getProviderDetails()
                .getUserInfoEndpoint().getUserNameAttributeName();

        OAuthAttributes attributes = OAuthAttributes.of(registrationId, userNameAttributeName, oAuth2User.getAttributes());

        User user = saveOrUpdate(attributes);
        httpSession.setAttribute("user", new SessionUser(user));

        return new DefaultOAuth2User(
                Collections.singleton(new SimpleGrantedAuthority(user.getRoleKey())),
                attributes.getAttributes(),
                attributes.getNameAttributeKey());
    }


    private User saveOrUpdate(OAuthAttributes attributes) {
        User user = (User) userRepository.findByToken(attributes.getToken())
                .map(entity -> entity.update(attributes.getName()))
                .orElse(attributes.toEntity());

        return userRepository.save(user);
    }
}

 

 

  • config/auth/SecurityConfig
package com.example.CoffeeShop.config.auth;

import lombok.RequiredArgsConstructor;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@RequiredArgsConstructor
//Spring Security 활성화
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final CustomOAuth2UserService customOAuth2UserService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().headers().frameOptions().disable() //h2 사용을 위한 옵션 비활성화
                .and().logout().logoutSuccessUrl("/") //로그아웃 성공 시 / 주소로 이동
                .and().oauth2Login().userInfoEndpoint().userService(customOAuth2UserService); //userInterface 구현체 등록
    }

}

 

 

  • config/auth/DTO/OAuthAttributes
package com.example.CoffeeShop.config.auth.DTO;

import com.example.CoffeeShop.Entity.UserManage.Role;
import com.example.CoffeeShop.Entity.User;
import lombok.Builder;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;

@Getter
@Slf4j
public class OAuthAttributes {
    private Map<String, Object> attributes;
    private String nameAttributeKey;
    private String name;
    private String token;
    private String birth;
    private String phoneNum;

    @Builder
    public OAuthAttributes(Map<String, Object> attributes, String nameAttributeKey, String name, String token, String birth, String phoneNum) {
        this.attributes = attributes;
        this.nameAttributeKey = nameAttributeKey;
        this.name = name;
        this.token = token;
        this.birth = birth;
        this.phoneNum = phoneNum;
    }

    public static OAuthAttributes of(String registrationId, String userNameAttributeName, Map<String, Object> attributes) {

        if ("naver".equals(registrationId)) {
            return ofNaver("id", attributes);
        }
        return ofGoogle(userNameAttributeName, attributes);
    }

    private static OAuthAttributes ofGoogle(String userNameAttributeName, Map<String, Object> attributes) {

        log.info("attribute : " +attributes);

        return OAuthAttributes.builder()
                .name((String) attributes.get("name"))
                .token((String) attributes.get("email"))
                .birth((String) attributes.get("age"))
                .attributes(attributes)
                .nameAttributeKey(userNameAttributeName)
                .build();
    }

    private static OAuthAttributes ofNaver(String userNameAttributeName, Map<String, Object> attributes) {
        Map<String, Object> response = (Map<String, Object>)attributes.get("response");

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


        return OAuthAttributes.builder()
                .name((String) response.get("name"))
                .token((String) response.get("id"))
                .phoneNum((String) response.get("mobile"))
                .birth((String) response.get("birthyear"))
                .attributes(response)
                .nameAttributeKey(userNameAttributeName)
                .build();
    }

    public User toEntity() {
        return User.builder()
                .name(name)
                .token(token)
                .phoneNum(phoneNum)
                .birth(birth)
                .role(Role.GUEST)
                .build();
    }
}

 

 

  • config/auth/DTO/SessionUser
package com.example.CoffeeShop.config.auth.DTO;

import com.example.CoffeeShop.Entity.User;
import lombok.Getter;

import java.io.Serializable;

@Getter
public class SessionUser implements Serializable {
    private String name;
    private String token;

    public SessionUser(User user) {
        this.name = user.getName();
        this.token = user.getToken();
    }
}

 

 

  • config/auth/LoginUser
package com.example.CoffeeShop.config.auth;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.PARAMETER) //어노테이션이 생성될 수 있는 위치 지정
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginUser {
}

 

 

  • config/auth/LoginUserArgumentResolver
package com.example.CoffeeShop.config.auth;

import com.example.CoffeeShop.config.auth.DTO.SessionUser;
import lombok.RequiredArgsConstructor;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import javax.servlet.http.HttpSession;

@RequiredArgsConstructor
@Component
public class LoginUserArgumentResolver implements HandlerMethodArgumentResolver {

    private final HttpSession httpSession;

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        boolean isLoginUserAnnotation = parameter.getParameterAnnotation(LoginUser.class) != null;
        boolean isUserClass = SessionUser.class.equals(parameter.getParameterType());

        return isLoginUserAnnotation && isUserClass;
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer modelAndViewContainer,
                                  NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        return httpSession.getAttribute("user");
    }
}

 

 

 

  • 뷰 페이지

Main
Login
네이버 API
로그인 완료 후 메인

 

 

 

프로젝트 구조

 

 

 

 

GitHub - Pearlmoon997/CoffeeShop: CoffeeShop

CoffeeShop. Contribute to Pearlmoon997/CoffeeShop development by creating an account on GitHub.

github.com

 

'프로젝트_ 커피주문 서비스' 카테고리의 다른 글

마이페이지  (0) 2022.08.31
주문하기 구현  (0) 2022.08.28
레이아웃, Member 변경  (0) 2022.08.11
Store - Order 연결  (0) 2022.08.09
Store CRUD  (0) 2022.08.08