본문 바로가기
Learning-log/Spring & JPA

[Spring Boot] Spring Security oauth2login 설정으로 Kakao 소셜로그인 API 구현하기 (DeafaultOAuth2User 확장)

by why제곱 2023. 9. 19.

JWT

1. 설정

  1. build.gradle에 dependency 추가하기
implementation 'com.auth0:java-jwt:4.4.0'

1) Dependency 추가

  • build.gradle
  • dependencies { implementation 'org.springframework.boot:spring-boot-starter-security' }
  • Maven Project
  • <dependencies> <!-- ... other dependency elements ... --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> </dependencies>
  1. application.properties
#JWT 설정

jwt.secretKey=F22rV7dQ4uHx2P6gv5lsJrE8mUcYn2023

# Access Token Configuration
#1시간(60분) (1000L(ms -> s) * 60L(s -> m) * 60L(m -> h))
jwt.access.expiration=3600000 
jwt.access.header=Authorization

# Refresh Token Configuration
# (1000L(ms -> s) * 60L(s -> m) * 60L(m -> h) * 24L(h -> 하루) * 14(2주))
jwt.refresh.expiration=1209600000 
jwt.refresh.header=Authorization-refresh

2. JwtService

  1. application.properties에서 설정한 값
		@Value("${jwt.secretKey}")
    private String secretKey;

    @Value("${jwt.access.expiration}")
    private Long accessTokenExpirationPeriod;

    @Value("${jwt.refresh.expiration}")
    private Long refreshTokenExpirationPeriod;

    @Value("${jwt.access.header}")
    private String accessHeader;

    @Value("${jwt.refresh.header}")
    private String refreshHeader;

SocialLogin

1. Resource Server에 Application 등록

카카오 또는 네이버에 애플리케이션 등록

애플리케이션 - NAVER Developers

 

2. application.properties 작성

# Google OAuth2
spring.security.oauth2.client.registration.google.client-id=구글 클라이언트 ID
spring.security.oauth2.client.registration.google.client-secret=구글 클라이언트 Secret
spring.security.oauth2.client.registration.google.scope=profile,email

# Naver OAuth2
spring.security.oauth2.client.registration.naver.client-id=네이버 클라이언트 ID
spring.security.oauth2.client.registration.naver.client-secret=네이버 클라이언트 Secret
spring.security.oauth2.client.registration.naver.redirect-uri=http://localhost:8080/login/oauth2/code/naver
spring.security.oauth2.client.registration.naver.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.naver.scope=name,email,profile_image
spring.security.oauth2.client.registration.naver.client-name=Naver

# Kakao OAuth2
spring.security.oauth2.client.registration.kakao.client-id=카카오 클라이언트 ID
spring.security.oauth2.client.registration.kakao.client-secret=카카오 클라이언트 Secret
spring.security.oauth2.client.registration.kakao.redirect-uri=http://localhost:8080/login/oauth2/code/kakao
spring.security.oauth2.client.registration.kakao.client-authentication-method=POST
spring.security.oauth2.client.registration.kakao.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.kakao.scope=profile_nickname,profile_image
spring.security.oauth2.client.registration.kakao.client-name=Kakao

# Naver OAuth2 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
spring.security.oauth2.client.provider.naver.user-name-attribute=response

# Kakao OAuth2 Provider
spring.security.oauth2.client.provider.kakao.authorization-uri=https://kauth.kakao.com/oauth/authorize
spring.security.oauth2.client.provider.kakao.token-uri=https://kauth.kakao.com/oauth/token
spring.security.oauth2.client.provider.kakao.user-info-uri=https://kapi.kakao.com/v2/user/me
spring.security.oauth2.client.provider.kakao.user-name-attribute=id
  • registration 부분
    • OAuth 로그인 시 설정한 Application의 정보를 사용하여 AccessToken을 Authorization Server에게 발급받을 때 사용
  • provider 부분
    • AccessToken을 Authorization Server에게 발급 받은 후, 해당 AccessToken으로 Resource Server의 API를 사용할 때
    • provider 부분의 정보를 사용하여 API 호출

3. 관련 클래스 생성

CustomOAuth2User

  • OAuth2UserService에서 사용할 OAuth2User 객체 커스텀한 클래스
  • 필요한 필드(닉네임) 추가하기 때문에 커스텀 필요
/**
 * DefaultOAuth2User를 상속하고, nickname 필드를 추가로 가진다.
 */
@Getter
public class CustomOAuth2User extends DefaultOAuth2User {

    private String nickname;
 

    /**
     * Constructs a {@code DefaultOAuth2User} using the provided parameters.
     *
     * @param authorities      the authorities granted to the user
     * @param attributes       the attributes about the user
     * @param nameAttributeKey the key used to access the user's &quot;name&quot; from
     *                         {@link #getAttributes()}
     */
    public CustomOAuth2User(Collection<? extends GrantedAuthority> authorities,
                            Map<String, Object> attributes, String nameAttributeKey,
                            String nickname) {
        super(authorities, attributes, nameAttributeKey);
        this.nickname= nickname;
       
    }
}

Oauth DTO 클래스 - OAuthAttributes

  • 소셜에서 받아오는 데이터가 다르므로 소셜별로 데이터를 받는 데이터를 분기 처리하는 DTO
  • 이번 프로젝트는 카카오만 진행하므로 카카오 데이터 받는 부분만 구현하면 됨.
package login.oauthtest4.global.oauth2;

import login.oauthtest4.domain.user.Role;
import login.oauthtest4.domain.user.SocialType;
import login.oauthtest4.domain.user.User;
import login.oauthtest4.global.oauth2.userinfo.GoogleOAuth2UserInfo;
import login.oauthtest4.global.oauth2.userinfo.KakaoOAuth2UserInfo;
import login.oauthtest4.global.oauth2.userinfo.NaverOAuth2UserInfo;
import login.oauthtest4.global.oauth2.userinfo.OAuth2UserInfo;
import lombok.Builder;
import lombok.Getter;

import java.util.Map;
import java.util.UUID;

/**
 * 각 소셜에서 받아오는 데이터가 다르므로
 * 소셜별로 데이터를 받는 데이터를 분기 처리하는 DTO 클래스
 */
@Getter
public class OAuthAttributes {

    private String nameAttributeKey; // OAuth2 로그인 진행 시 키가 되는 필드 값, PK와 같은 의미
    private OAuth2UserInfo oauth2UserInfo; // 소셜 타입별 로그인 유저 정보(닉네임, 이메일, 프로필 사진 등등)

    @Builder
    public OAuthAttributes(String nameAttributeKey, OAuth2UserInfo oauth2UserInfo) {
        this.nameAttributeKey = nameAttributeKey;
        this.oauth2UserInfo = oauth2UserInfo;
    }

    /**
     * SocialType에 맞는 메소드 호출하여 OAuthAttributes 객체 반환
     * 파라미터 : userNameAttributeName -> OAuth2 로그인 시 키(PK)가 되는 값 / attributes : OAuth 서비스의 유저 정보들
     * 소셜별 of 메소드(ofGoogle, ofKaKao, ofNaver)들은 각각 소셜 로그인 API에서 제공하는
     * 회원의 식별값(id), attributes, nameAttributeKey를 저장 후 build
     */

    private static OAuthAttributes ofKakao(String userNameAttributeName, Map<String, Object> attributes) {
        return OAuthAttributes.builder()
                .nameAttributeKey(userNameAttributeName)
                .oauth2UserInfo(new KakaoOAuth2UserInfo(attributes))
                .build();
    }

    /**
     * of메소드로 OAuthAttributes 객체가 생성되어, 유저 정보들이 담긴 OAuth2UserInfo가 소셜 타입별로 주입된 상태
     * OAuth2UserInfo에서 socialId(식별값), nickname, imageUrl을 가져와서 build
     * email에는 UUID로 중복 없는 랜덤 값 생성
     * role은 GUEST로 설정
     */
    public User toEntity(SocialType socialType, OAuth2UserInfo oauth2UserInfo) {
        return User.builder()
                .socialType(socialType)
                .socialId(oauth2UserInfo.getId())
                .email(UUID.randomUUID() + "@socialUser.com")
                .nickname(oauth2UserInfo.getNickname())
                .imageUrl(oauth2UserInfo.getImageUrl())
                .role(Role.GUEST)
                .build();
    }
}