kakao 소셜 로그인 하는법

알파로그·2023년 4월 4일
0

Spring Boot

목록 보기
34/57

✏️ 환경설정

📍 디팬던시 추가

  • 소셜 로그인에 관련된 라이브러리
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'

📍 application yml 설정 추가

  • setting
spring:
  security:
    oauth2:
      client:
        registration:
          kakao:
            clientId: 2d3b2262f9b1320d66b91a31d866c35b
            scope:
            client-name: Kakao
            authorization-grant-type: authorization_code
            redirect-uri: http://localhost:8080/login/oauth2/code/kakao
            client-authentication-method: POST
        provider:
          kakao:
            authorization-uri: https://kauth.kakao.com/oauth/authorize
            token-uri: https://kauth.kakao.com/oauth/token
            user-info-uri: https://kapi.kakao.com/v2/user/me
            user-name-attribute: id
  • 설명
spring:
  security:
    oauth2:
      client:
        registration:
          kakao:
            clientId: # REST API 키
            scope: # Kakao 로 부터 받
            client-name: Kakao
            authorization-grant-type: authorization_code
            redirect-uri: # redirect UrL - 요청완료후 응답이 리다이렉트 되는 url
            client-authentication-method: # HTTP method
        provider:
          kakao:
            authorization-uri: https://kauth.kakao.com/oauth/authorize
            token-uri: https://kauth.kakao.com/oauth/token
            user-info-uri: https://kapi.kakao.com/v2/user/me
            user-name-attribute: id

✏️ Kakao 개발자 도구

📍 앱 생성

🔗 개발자 도구 링크

  • 내 어플리케이션 → 로그인 → 어플리케이션 추가 → 접속

📍 카카오 로그인 활성화

  • 매뉴 → 카카오 로그인 → 활성화 설정 → 상태 on 으로 변경
  • 하단의 Redirect URL 등록
    • application yml 에 등록했던 url 을 입력

      redirect-uri: http://localhost:8080/login/oauth2/code/kakao

📍 앱 키 등록

  • 매뉴 → 요약 정보 → REST API 키 복사
  • application yml 에 입력
kakao:
  clientId: 2d3b2262f9b1320d66b91a31d866c35b

📍 Security 설정

  • Configuration 계층의 로그인 설정에서 소셜 로그인 로직도 추가해준다.
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
    @Bean
    SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .formLogin(  // Security 자체 로그인
                        formLogin -> formLogin
                                .loginPage("/member/login")
                )
                .oauth2Login(  // 소셜 로그인
                        oauth2Login -> oauth2Login
                                .loginPage("/member/login")
                )
                .logout(
                        logout -> logout
                                .logoutUrl("/member/logout")
                );

        return http.build();
    }

✏️ 구현하기

📍 kakao 로그인 요청하기

  • html 버튼 생성하기
    • 세팅할 때 appliction yml 에 설정해둔 url 로 요청을 보내는 링크를 생성한다.
  • 클라이언트가 해당 링크를 누르면 kakao 에서 나머지 작업을 처리해준다.
<a href="/oauth2/authorization/kakao">
    카카오로 로그인하기
</a>

📍 Entity 계층

  • Member Entity 에 새로운 필드를 추가해준다.
    • 어떤 방식으로 소셜로그인 했는지 기록하기 위한 속성이다.
// 일반회원인지, 카카오로 가입한 회원인지, 구글로 가입한 회원인지
private String providerTypeCode;

📍 Service 계층

  • member service 에 로그인과 소셜 로그인을 내부적으로 처리하는 공통로직을 새로 추가한다.
    • private 주의!!
  • method 역할
    • member name 이 중복되었는지 확인
    • Security 로그인일경우 password 인코딩
      • password 의 유무로 로그인의 종류를 파악할 수 있음
    • 새로운 객체 생성후 db 에 저장
//-- login 처리 로직 --//
// 내부 처리함수, 일반회원가입, 소셜로그인을 통한 회원가입(최초 로그인 시 한번만 발생)에서 이 함수를 사용함
private RsData<Member> join(String providerTypeCode, String username, String password) {

    // name 중복 체크 //
    if (findByUsername(username).isPresent())
        return RsData.of("F-1", "해당 아이디(%s)는 이미 사용중입니다.".formatted(username));

    // 소셜 로그인을 통한 회원가입에서는 비번이 없다. //
    if (StringUtils.hasText(password)) 
				password = passwordEncoder.encode(password);

    // 수동으로 새로운 member 객체 생성 //
    Member member = Member
            .builder()
            .providerTypeCode(providerTypeCode)
            .username(username)
            .password(password)
            .build();

		// member 객체 db 에 저장 //
    memberRepository.save(member);

    return RsData.of("S-1", "회원가입이 완료되었습니다.", member);
}

  • 방금 만든 로그인 공통로직을 사용하는 business 로직을 생성
  1. Security 로그인
    • name 과 pw 를 매개변수로 받아 join 을 호출한다.
  2. Social 로그인
    • entity 에서 생성해준 providerTypeCode 값을 매개변수로 받는다.
//-- security join --//
@Transactional
public RsData<Member> join(String username, String password) {

    // "S-1.1" 해당 회원이 일반회원가입으로 인해 생성되었다는걸 나타내기 위해서
    return join("S-1.1", username, password);
}

//-- social join --//
// 소셜 로그인(카카오, 구글, 네이버) 로그인이 될 때 마다 실행되는 함수
@Transactional
public RsData<Member> whenSocialLogin(String providerTypeCode, String username) {

		// username 예시 : KAKAO__1312319038130912, NAVER__1230812300
    Optional<Member> opMember = findByUsername(username); 

    // 아이디가 있는경우
    if (opMember.isPresent()) 
				return RsData.of("S-2", "로그인 되었습니다.", opMember.get());

    // 소셜 로그인를 통한 가입시 비번은 없다.
    return join(providerTypeCode, username, ""); // 최초 로그인 시 딱 한번 실행
}

📍 Security 계층

  • 소셜 로그인 처리기능만 담당하는 Security 계층을 새로 생성한다.
    • REST API 로 응답받은 data 를 DB 에 저장하는 역할이다.
    • DefaultOAuth2UserService 를 상속받았다.
package com.ll.gramgram.base.security;

import com.ll.gramgram.boundedContext.member.entity.Member;
import com.ll.gramgram.boundedContext.member.service.MemberService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.Map;

@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
@Slf4j
public class CustomOAuth2UserService extends DefaultOAuth2UserService {

    // 소셜 로그인을 할 Member 의 Service 계층 객체를 DI 해야 한다.
    private final MemberService memberService;

    // 소셜 로그인을 처리하기 위해 필요한 라이브러리
		// 자세한 역할은 모르겠다.
		class CustomOAuth2User extends User implements OAuth2User {
		
		    public CustomOAuth2User(String username, String password, Collection<? extends GrantedAuthority> authorities) {
		        super(username, password, authorities);
		    }
		
		    @Override
		    public Map<String, Object> getAttributes() {
		        return null;
		    }
		
		    @Override
		    public String getName() {
		        return getUsername();
		    }
}

  • 소셜로그인이 성공했을 때 실행되는 method
    • CustomOAuth2UserService 의 method 로 생성해주면 된다.
@Override
@Transactional
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
    OAuth2User oAuth2User = super.loadUser(userRequest);

		// id
    String oauthId = oAuth2User.getName();

		// providerTypeCode
    String providerTypeCode = userRequest.getClientRegistration().getRegistrationId().toUpperCase();

		// name
    String username = providerTypeCode + "__%s".formatted(oauthId);

		// service 로직을 통한 객체 생성
    Member member = memberService.whenSocialLogin(providerTypeCode, username).getData();

    return new CustomOAuth2User(member.getUsername(), member.getPassword(), member.getGrantedAuthorities());
}

⚠️ 추후에 카카오에 정식적으로 승인받기 위해선 공식 버튼 ui 를 사용해야 한다.
🔗 카카오 디자인 리소스

profile
잘못된 내용 PR 환영

0개의 댓글