Spring-Security-6

akanana·2023년 3월 6일
0

Spring-Security

목록 보기
7/8

목표

  • OAuth 로그인/회원가입 처리

문제발생

Spring-Security4에서 Google API에 대한 로그인, 회원가입 처리를 완료하였다
하지만 뒤에 추가적으로 FaceBook, Naver, Kakao API를 추가하였고, 이에 대한 로그인, 회원가입 처리를 하게되었다
attributes

# 구글
attributes : {sub={고유 id}, name={이름}, given_name={이름}, family_name={}, picture={프로필사진}, email={이메일}, email_verified=true, locale=ko}
# 페이스북
attributes : {id={고유 id}, name={이름}, email={이메일}}
# 네이버
attributes : {resultcode=00, message=success, response={id={고유 ID}, email={이메일}, name={이름}}}
#카카오
attributes : {id={고유 id}, connected_at={접근시간}, properties={nickname=.}, kakao_account={profile_nickname_needs_agreement=false, profile_image_needs_agreement=true, profile={nickname=.}, has_email=true, email_needs_agreement=false, is_email_valid=true, is_email_verified=true, email={이메일}}}

하지만 위처럼 attribute를 받아온 결과, attributes값들이 서로 상이함을 알 수 있다
이를 위해 DefaultOAuth2UserService를 상속받은 클래스에서 loadUser가 실행될때 각 서비스별로 별도의 처리가 필요하다

이를 위해 하나의

@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
    OAuth2User oAuth2User = super.loadUser(userRequest);
    OAuth2UserInfo oAuth2UserInfo = null;
    switch (userRequest.getClientRegistration().getRegistrationId()) {
        case "google":
            oAuth2UserInfo = new GoogleUserInfo(oAuth2User.getAttributes());
            break;
        case "facebook":
            oAuth2UserInfo = new FacebookUserInfo(oAuth2User.getAttributes());
            break;
        case "naver":
            oAuth2UserInfo = new NaverUserInfo((Map)oAuth2User.getAttributes().get("response"));
            break;
        case "kakao":
            oAuth2UserInfo = new KakaoUserInfo(oAuth2User.getAttributes());
            break;
        default:
            log.info("지원하지 않는 OAuth 입니다");
            break;
    }
    Optional<User> userOptional = userRepository.findByProviderAndProviderId(oAuth2UserInfo.getProvider(),
            oAuth2UserInfo.getProviderId());

    User user;
    if (userOptional.isPresent()) {
        user = userOptional.get();
        user.setEmail(oAuth2UserInfo.getEmail());
        userRepository.save(user);
    } else {
        user = User.builder()
                .username(oAuth2UserInfo.getProvider() + "_" + oAuth2UserInfo.getProviderId())
                .email(oAuth2UserInfo.getEmail())
                .password(passwordEncoder.encode("패스워드"))
                .role("ROLE_USER")
                .provider(oAuth2UserInfo.getProvider())
                .providerId(oAuth2UserInfo.getProviderId())
                .build();
        userRepository.save(user);
    }

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

이를 위해 위처럼 oAuth2UserInfo 인터페이스를 생성하여, 서비스별로 별도의 값을 받는 처리를 해주었다

OAuth2UserInfo

OAuth2UserInfo

public interface OAuth2UserInfo {
    String getProviderId();
    String getProvider();
    String getEmail();
    String getName();
}

FacebookUserInfo

import java.util.Map;

public class FacebookUserInfo implements OAuth2UserInfo {
    private Map<String, Object> attributes;

    public FacebookUserInfo(Map<String, Object> attributes){
        this.attributes = attributes;
    }
    @Override
    public String getProviderId() {
        return (String)attributes.get("id");
    }

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

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

    @Override
    public String getName() {
        return (String)attributes.get("name");
    }
}
import java.util.Map;

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)attributes.get("id");
    }

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

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

GoogleUserInfo

import java.util.Map;

public class GoogleUserInfo implements OAuth2UserInfo{

    private Map<String, Object> attributes;

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

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

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

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

KakaoUserInfo

import java.util.Map;

public class KakaoUserInfo implements OAuth2UserInfo{

    private Map<String, Object> attributes;
    private Map<String, Object> accountAttributes;
    private Map<String, Object> propertiesAttributes;

    public KakaoUserInfo(Map<String, Object> attributes){
        this.attributes = attributes;
        this.accountAttributes = (Map)attributes.get("kakao_account");
        this.propertiesAttributes = (Map)attributes.get("properties");
    }
    
    @Override
    public String getProviderId() {
        return attributes.get("id").toString();
    }
    
    @Override
    public String getProvider() {
        return "kakao";
    }

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

    @Override
    public String getName() {
        return (String)propertiesAttributes.get("nickname");
    } 
}

이 외 oAuth2User.getAttributes() 값을 확인하여 필요에 따라 메소드를 수정하자

0개의 댓글