Skip to content

Commit

Permalink
feat: #11 #45 kakao OIDC 로그인 로직 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
psychology50 committed Dec 23, 2023
1 parent 97e52e4 commit 21a9463
Show file tree
Hide file tree
Showing 47 changed files with 383 additions and 191 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-parent:2.7.10'
implementation 'com.jcraft:jsch:0.1.55'

implementation 'org.apache.httpcomponents:httpclient:4.5.14'
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/kcy/fitapet/FitapetApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
import jakarta.annotation.PostConstruct;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

import java.util.TimeZone;

@SpringBootApplication
@EnableJpaRepositories(repositoryFactoryBeanClass = ExtendedJpaRepositoryFactory.class)

public class FitapetApplication {
public static void main(String[] args) {
SpringApplication.run(FitapetApplication.class, args);
Expand Down
10 changes: 5 additions & 5 deletions src/main/java/com/kcy/fitapet/domain/member/api/AuthApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
import com.kcy.fitapet.global.common.response.code.ErrorCode;
import com.kcy.fitapet.global.common.response.exception.GlobalErrorException;
import com.kcy.fitapet.global.common.util.cookie.CookieUtil;
import com.kcy.fitapet.global.common.util.jwt.AuthConstants;
import com.kcy.fitapet.global.common.util.jwt.exception.AuthErrorCode;
import com.kcy.fitapet.global.common.util.jwt.exception.AuthErrorException;
import com.kcy.fitapet.global.common.security.jwt.AuthConstants;
import com.kcy.fitapet.global.common.security.jwt.exception.AuthErrorCode;
import com.kcy.fitapet.global.common.security.jwt.exception.AuthErrorException;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
Expand All @@ -42,8 +42,8 @@

import java.util.Map;

import static com.kcy.fitapet.global.common.util.jwt.AuthConstants.ACCESS_TOKEN;
import static com.kcy.fitapet.global.common.util.jwt.AuthConstants.REFRESH_TOKEN;
import static com.kcy.fitapet.global.common.security.jwt.AuthConstants.ACCESS_TOKEN;
import static com.kcy.fitapet.global.common.security.jwt.AuthConstants.REFRESH_TOKEN;

@Tag(name = "유저 관리 API", description = "유저 인증과 관련된 API")
@RestController
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
import com.kcy.fitapet.global.common.response.code.ErrorCode;
import com.kcy.fitapet.global.common.response.code.StatusCode;
import com.kcy.fitapet.global.common.response.exception.GlobalErrorException;
import com.kcy.fitapet.global.common.util.jwt.JwtUtil;
import com.kcy.fitapet.global.common.util.jwt.dto.JwtUserInfo;
import com.kcy.fitapet.global.common.util.jwt.dto.SmsAuthInfo;
import com.kcy.fitapet.global.common.security.jwt.JwtUtil;
import com.kcy.fitapet.global.common.security.jwt.dto.JwtUserInfo;
import com.kcy.fitapet.global.common.security.jwt.dto.SmsAuthInfo;
import com.kcy.fitapet.global.common.redis.forbidden.ForbiddenTokenService;
import com.kcy.fitapet.global.common.redis.refresh.RefreshToken;
import com.kcy.fitapet.global.common.redis.refresh.RefreshTokenService;
Expand All @@ -33,8 +33,8 @@
import java.time.LocalDateTime;
import java.util.Map;

import static com.kcy.fitapet.global.common.util.jwt.AuthConstants.ACCESS_TOKEN;
import static com.kcy.fitapet.global.common.util.jwt.AuthConstants.REFRESH_TOKEN;
import static com.kcy.fitapet.global.common.security.jwt.AuthConstants.ACCESS_TOKEN;
import static com.kcy.fitapet.global.common.security.jwt.AuthConstants.REFRESH_TOKEN;

@Slf4j
@Service
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package com.kcy.fitapet.domain.oauth.api;

import com.kcy.fitapet.domain.member.dto.auth.SignInReq;
import com.kcy.fitapet.domain.oauth.dto.OauthSignInReq;
import com.kcy.fitapet.domain.oauth.dto.OauthSignUpReq;
import com.kcy.fitapet.domain.oauth.service.OAuthService;
import com.kcy.fitapet.domain.oauth.service.component.OauthService;
import com.kcy.fitapet.domain.oauth.type.ProviderType;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
Expand All @@ -17,8 +16,8 @@
@RequiredArgsConstructor
@RequestMapping("/api/v1/auth/oauth")
@Slf4j
public class OAuthApi {
private final OAuthService oAuthService;
public class OauthApi {
private final OauthService oAuthService;

@PostMapping("")
@PreAuthorize("isAnonymous()")
Expand All @@ -40,6 +39,10 @@ public void signUp(
@RequestParam("provider") ProviderType provider,
@RequestBody @Valid OauthSignUpReq req
) {
if (ProviderType.NAVER.equals(provider)) {

} else {

}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.kcy.fitapet.domain.oauth.dao;

import com.kcy.fitapet.domain.oauth.domain.OauthAccount;
import com.kcy.fitapet.domain.oauth.type.ProviderType;
import com.kcy.fitapet.global.common.repository.ExtendedRepository;

import java.util.Optional;

public interface OauthRepository extends ExtendedRepository<OauthAccount, Long> {
Optional<OauthAccount> findByOauthIdAndProvider(Long oauthId, ProviderType provider);
boolean existsByOauthIdAndProvider(Long oauthId, ProviderType provider);
boolean existsByEmail(String email);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,16 @@
import lombok.*;

@Entity
@Getter
@Table(name = "OAUTH")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@ToString(of = {"id", "provider"})
public class OAuthAccount extends Auditable {
public class OauthAccount extends Auditable {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "oauth_id")
private Long OAuthID;
private Long OauthId;
@Convert(converter = ProviderTypeConverter.class)
private ProviderType provider;
private String email;
Expand All @@ -26,17 +27,17 @@ public class OAuthAccount extends Auditable {
private Member member;

@Builder
public OAuthAccount(Long id, Long OAuthID, ProviderType provider, String email, Member member) {
public OauthAccount(Long id, Long OauthId, ProviderType provider, String email, Member member) {
this.id = id;
this.OAuthID = OAuthID;
this.OauthId = OauthId;
this.provider = provider;
this.email = email;
this.member = member;
}

public static OAuthAccount of(Long OAuthID, ProviderType provider, String email, Member member) {
return OAuthAccount.builder()
.OAuthID(OAuthID)
public static OauthAccount of(Long OauthId, ProviderType provider, String email, Member member) {
return OauthAccount.builder()
.OauthId(OauthId)
.provider(provider)
.email(email)
.member(member)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ public record OauthSignInReq(
@NotEmpty
String id,
@NotEmpty
String id_token
String id_token,
@NotEmpty
String nonce
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.kcy.fitapet.domain.oauth.exception;

import com.kcy.fitapet.global.common.response.code.StatusCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;

@Getter
@RequiredArgsConstructor
public enum OauthException implements StatusCode {
/* BAD REQUEST */
INVALID_PROVIDER(HttpStatus.BAD_REQUEST, "유효하지 않은 제공자입니다."),

/* FORBIDDEN */
NOT_FOUND_MEMBER(HttpStatus.FORBIDDEN, "존재하지 않는 회원입니다.");

private final HttpStatus httpStatus;
private final String message;


@Override
public String getName() {
return name();
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.kcy.fitapet.domain.oauth.service.component;

import com.kcy.fitapet.domain.member.domain.Member;
import com.kcy.fitapet.domain.oauth.service.module.OauthApplicationConfigHelper;
import com.kcy.fitapet.domain.oauth.service.module.OauthClientHelper;
import com.kcy.fitapet.domain.oauth.service.module.OauthSearchService;
import com.kcy.fitapet.domain.oauth.type.ProviderType;
import com.kcy.fitapet.global.common.security.jwt.JwtUtil;
import com.kcy.fitapet.global.common.security.jwt.dto.Jwt;
import com.kcy.fitapet.global.common.security.jwt.dto.JwtUserInfo;
import com.kcy.fitapet.global.common.security.oauth.OauthApplicationConfig;
import com.kcy.fitapet.global.common.security.oauth.OauthClient;
import com.kcy.fitapet.global.common.security.oauth.OauthOIDCHelper;
import com.kcy.fitapet.global.common.security.oauth.dto.OIDCDecodePayload;
import com.kcy.fitapet.global.common.security.oauth.dto.OIDCPublicKeyResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Slf4j
public class OauthService {
private final OauthSearchService oauthSearchService;

private final OauthOIDCHelper oauthOIDCHelper;
private final OauthClientHelper oauthClientHelper;
private final OauthApplicationConfigHelper oauthApplicationConfigHelper;

private final JwtUtil jwtUtil;

@Transactional
public void signUpByOIDC() {

}

@Transactional
public Jwt signInByOIDC(String id, String idToken, ProviderType provider, String nonce) {
OauthClient oauthClient = oauthClientHelper.getOauthClient(provider);
OIDCPublicKeyResponse oidcPublicKeyResponse = oauthClient.getOIDCPublicKey();
OauthApplicationConfig oauthApplicationConfig = oauthApplicationConfigHelper.getOauthApplicationConfig(provider);

OIDCDecodePayload payload = oauthOIDCHelper.getPayloadFromIdToken(
idToken, oauthApplicationConfig.getAuthorizationUri(),
oauthApplicationConfig.getClientId(), nonce, oidcPublicKeyResponse);

if (oauthSearchService.isExistMember(Long.parseLong(payload.sub()), provider)) {
Member member = oauthSearchService.findMemberByOauthIdAndProvider(Long.parseLong(payload.sub()), provider);
return generateToken(JwtUserInfo.from(member));
} else {
return null;
}
}

@Transactional
public void signInByCode() {

}

@Transactional
public void signUpByCode() {

}

private Jwt generateToken(JwtUserInfo jwtUserInfo) {
return Jwt.builder()
.accessToken(jwtUtil.generateAccessToken(jwtUserInfo))
.refreshToken(jwtUtil.generateRefreshToken(jwtUserInfo))
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.kcy.fitapet.domain.oauth.service.module;

import com.kcy.fitapet.domain.oauth.exception.OauthException;
import com.kcy.fitapet.domain.oauth.type.ProviderType;
import com.kcy.fitapet.global.common.response.exception.GlobalErrorException;
import com.kcy.fitapet.global.common.security.oauth.OauthApplicationConfig;
import com.kcy.fitapet.global.common.security.oauth.kakao.KakaoApplicationConfig;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class OauthApplicationConfigHelper {
private final KakaoApplicationConfig kakaoApplicationConfig;

public OauthApplicationConfig getOauthApplicationConfig(ProviderType provider) {
return switch (provider) {
case KAKAO -> kakaoApplicationConfig;
case GOOGLE -> null;
case APPLE -> null;
case NAVER -> null;
default -> throw new GlobalErrorException(OauthException.INVALID_PROVIDER);
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.kcy.fitapet.domain.oauth.service.module;

import com.kcy.fitapet.domain.oauth.exception.OauthException;
import com.kcy.fitapet.domain.oauth.type.ProviderType;
import com.kcy.fitapet.global.common.response.exception.GlobalErrorException;
import com.kcy.fitapet.global.common.security.oauth.OauthClient;
import com.kcy.fitapet.global.common.security.oauth.kakao.KakaoOauthClient;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class OauthClientHelper {
private final KakaoOauthClient kakaoOauthClient;

public OauthClient getOauthClient(ProviderType provider) {
return switch (provider) {
case KAKAO -> kakaoOauthClient;
case GOOGLE -> null;
case APPLE -> null;
default -> throw new GlobalErrorException(OauthException.INVALID_PROVIDER);
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.kcy.fitapet.domain.oauth.service.module;

import com.kcy.fitapet.domain.member.domain.Member;
import com.kcy.fitapet.domain.oauth.dao.OauthRepository;
import com.kcy.fitapet.domain.oauth.domain.OauthAccount;
import com.kcy.fitapet.domain.oauth.exception.OauthException;
import com.kcy.fitapet.domain.oauth.type.ProviderType;
import com.kcy.fitapet.global.common.response.exception.GlobalErrorException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
public class OauthSearchService {
private final OauthRepository oauthRepository;

@Transactional(readOnly = true)
public boolean isExistMember(Long oauthId, ProviderType provider) {
return oauthRepository.existsByOauthIdAndProvider(oauthId, provider);
}

@Transactional(readOnly = true)
public boolean isExistEmail(String email) {
return oauthRepository.existsByEmail(email);
}

@Transactional(readOnly = true)
public Member findMemberByOauthIdAndProvider(Long oauthId, ProviderType provider) {
OauthAccount oauthAccount = oauthRepository.findByOauthIdAndProvider(oauthId, provider)
.orElseThrow(() -> new GlobalErrorException(OauthException.NOT_FOUND_MEMBER));
return oauthAccount.getMember();
}
}
Loading

0 comments on commit 21a9463

Please sign in to comment.