Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: social login & withdraw member #89

Merged
merged 6 commits into from
Feb 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,14 @@ public ApiResponse<Object> handleCustomException(CustomException e) {
.message(e.getMessage())
.build();
}

@ExceptionHandler(UnauthorizedException.class)
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public ApiResponse<Object> handleUnauthorizedException(UnauthorizedException e) {

return ApiResponse.builder()
.status(401)
.message(e.getMessage())
.build();
}
}
4 changes: 2 additions & 2 deletions src/main/java/com/fullcar/core/response/ErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ public enum ErrorCode {

/* 400 BAD REQUEST */
FAILED_TO_GENERATE_PUBLIC_KEY(BAD_REQUEST, "μ• ν”Œ κ³΅κ°œν‚€ 생성 쀑 문제 λ°œμƒ"),
FAILED_TO_GENERATE_APPLE_TOKEN(BAD_REQUEST, "μ• ν”Œ access Token 생성 쀑 문제 λ°œμƒ"),
EMAIL_ADDRESS_IN_BLACKLIST(BAD_REQUEST, "λΈ”λž™λ¦¬μŠ€νŠΈμ— μžˆλŠ” 이메일 μ£Όμ†Œμž…λ‹ˆλ‹€."),
CANNOT_SEND_TO_OWN_CARPOOL(BAD_REQUEST, "μžκΈ°μžμ‹ μ˜ μΉ΄ν’€μ—λŠ” μ‹ μ²­ν•  수 μ—†μŠ΅λ‹ˆλ‹€."),
DUPLICATED_FORM(BAD_REQUEST, "이미 μš”μ²­μ„ 보낸 μΉ΄ν’€μž…λ‹ˆλ‹€."),
Expand All @@ -23,7 +22,6 @@ public enum ErrorCode {
INVALID_FORM_STATE(BAD_REQUEST, "μœ νš¨ν•˜μ§€ μ•Šμ€ μ‹ μ²­μ„œ μƒνƒœμž…λ‹ˆλ‹€."),
EXISTED_CODE_IN_MAIL(BAD_REQUEST, "이미 인증번호λ₯Ό λ³΄λƒˆμŠ΅λ‹ˆλ‹€."),
NOT_MATCHED_CODE(BAD_REQUEST, "μΈμ¦λ²ˆν˜Έκ°€ μΌμΉ˜ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€."),
INVALID_SOCIAL_TYPE(BAD_REQUEST, "μœ νš¨ν•˜μ§€ μ•Šμ€ μ†Œμ…œ 둜그인 νƒ€μž… μž…λ‹ˆλ‹€."),

/* 401 UNAUTHORIZED */
UNAUTHORIZED_KAKAO_TOKEN(UNAUTHORIZED, "μœ νš¨ν•˜μ§€ μ•Šμ€ 카카였 토큰"),
Expand All @@ -32,6 +30,8 @@ public enum ErrorCode {
INVALID_CLAIMS(UNAUTHORIZED, "μ˜¬λ°”λ₯΄μ§€ μ•Šμ€ Claim"),
SIGNIN_REQUIRED(UNAUTHORIZED, "access, refreshToken λͺ¨λ‘ λ§Œλ£Œλ˜μ—ˆμŠ΅λ‹ˆλ‹€. 재둜그인이 ν•„μš”ν•©λ‹ˆλ‹€."),
INVALID_MEMBER(UNAUTHORIZED, "μœ νš¨ν•˜μ§€ μ•Šμ€ μœ μ €"),
INVALID_KAKAO_USER(UNAUTHORIZED, "이미 νƒˆν‡΄ μ²˜λ¦¬λ˜μ—ˆκ±°λ‚˜ μœ νš¨ν•˜μ§€ μ•Šμ€ 카카였 μœ μ €μž…λ‹ˆλ‹€."),
FAILED_TO_GENERATE_APPLE_REFRESH_TOKEN(UNAUTHORIZED, "μ• ν”Œ refresh Token 생성 쀑 문제 λ°œμƒ"),

/* 404 NOT FOUND */
NOT_EXIST_USER(NOT_FOUND, "μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” μ‚¬μš©μžμž…λ‹ˆλ‹€."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fullcar.core.config.jwt.JwtTokenProvider;
import com.fullcar.core.exception.BadRequestException;
import com.fullcar.core.exception.CustomException;
import com.fullcar.core.exception.UnauthorizedException;
import com.fullcar.core.response.ErrorCode;
import com.fullcar.member.application.member.MemberMapper;
Expand All @@ -19,14 +18,12 @@
import lombok.RequiredArgsConstructor;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.bouncycastle.openssl.PEMParser;
Expand Down Expand Up @@ -58,8 +55,8 @@ public class AppleAuthService {
@Value("${apple.client-id}")
private String clientId;

private static final String REQUEST_TOKEN_URL = "https://appleid.apple.com/auth/oauth2/v2/token";
private static final String REVOKE_TOKEN_URL = "https://appleid.apple.com/auth/oauth2/v2/revoke";
private static final String REQUEST_TOKEN_URL = "https://appleid.apple.com/auth/token";
private static final String REVOKE_TOKEN_URL = "https://appleid.apple.com/auth/revoke";

private final ObjectMapper objectMapper;
private final JwtTokenProvider jwtTokenProvider;
Expand Down Expand Up @@ -192,7 +189,7 @@ private String createClientSecret() throws IOException {
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(expirationDate)
.setAudience("https://appleid.apple.com")
.setSubject("com.fullcar.app")
.setSubject(clientId)
.signWith(SignatureAlgorithm.ES256, getPrivateKey())
.compact();
}
Expand All @@ -208,10 +205,7 @@ private PrivateKey getPrivateKey() throws IOException {
}

public AppleAuthTokenResponseDto requestAppleAuthToken(String code) throws IOException {
String secret = createClientSecret();
System.out.println(secret);

RestTemplate restTemplate = new RestTemplateBuilder().build();
RestTemplate restTemplate = new RestTemplate();
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("code", code);
params.add("client_id", clientId);
Expand All @@ -225,18 +219,15 @@ public AppleAuthTokenResponseDto requestAppleAuthToken(String code) throws IOExc

try {
ResponseEntity<AppleAuthTokenResponseDto> response = restTemplate.postForEntity(REQUEST_TOKEN_URL, httpEntity, AppleAuthTokenResponseDto.class);
System.out.println(response.getBody());
return response.getBody();
} catch (Exception e) {
System.out.println(e);
throw new IllegalArgumentException("Apple token error");
//throw new CustomException(ErrorCode.FAILED_TO_GENERATE_APPLE_TOKEN);
throw new UnauthorizedException(ErrorCode.FAILED_TO_GENERATE_APPLE_REFRESH_TOKEN);
}
}

// νšŒμ› νƒˆν‡΄
public void revoke(Member member) throws IOException {
RestTemplate restTemplate = new RestTemplateBuilder().build();
RestTemplate restTemplate = new RestTemplate();

MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("client_id", clientId);
Expand Down
76 changes: 73 additions & 3 deletions src/main/java/com/fullcar/member/application/auth/AuthService.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,78 @@
package com.fullcar.member.application.auth;


import com.fullcar.core.config.jwt.JwtExceptionType;
import com.fullcar.core.config.jwt.JwtTokenProvider;
import com.fullcar.core.exception.CustomException;
import com.fullcar.core.response.ErrorCode;
import com.fullcar.member.application.car.CarService;
import com.fullcar.member.domain.member.Member;
import com.fullcar.member.domain.member.MemberRepository;
import com.fullcar.member.domain.member.SocialType;
import com.fullcar.member.domain.member.service.MailService;
import com.fullcar.member.presentation.auth.dto.response.AuthResponseDto;
import com.fullcar.member.presentation.auth.dto.response.AuthTokenResponseDto;
import com.fullcar.member.presentation.auth.dto.response.SocialInfoResponseDto;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;

@Component
@RequiredArgsConstructor
public class AuthService {
private final JwtTokenProvider jwtTokenProvider;
private final MemberRepository memberRepository;
private final AppleAuthService appleAuthService;
private final KakaoAuthService kakaoAuthService;
private final CarService carService;
private final MailService mailService;

public AuthResponseDto socialLogin(SocialInfoResponseDto socialResponseDto) {
Member member = memberRepository.findBySocialId(socialResponseDto.getSocialId());
String accessToken = jwtTokenProvider.generateAccessToken(member);

return AuthResponseDto.builder()
.accessToken(accessToken)
.refreshToken(socialResponseDto.getRefreshToken())
.build();
}

public AuthTokenResponseDto getNewToken(String refreshToken) {
// refresh 만료
if (jwtTokenProvider.validateToken(refreshToken) == JwtExceptionType.EXPIRED_JWT_TOKEN) {
throw new CustomException(ErrorCode.SIGNIN_REQUIRED);
}

// ν•΄λ‹Ή refreshToken을 가진 멀버가 μ‘΄μž¬ν•˜λŠ”μ§€ 확인
Member member = memberRepository.findByRefreshTokenOrThrow(refreshToken);
String newAccessToken = jwtTokenProvider.generateAccessToken(member);

return AuthTokenResponseDto.builder()
.accessToken(newAccessToken)
.refreshToken(refreshToken)
.build();
}

@Transactional
public void socialLogout(Member member) {
memberRepository.findByIdAndIsDeletedOrThrow(member.getId(), false).clearRefreshTokenAndDeviceToken();
memberRepository.flush();
}

@Transactional
public void withdrawMember(Member member) throws IOException {
if (member.getSocialType() == SocialType.APPLE) {
appleAuthService.revoke(member);
}
else if (member.getSocialType() == SocialType.KAKAO) {
kakaoAuthService.revoke(member);
}

carService.deleteCar(member.getCarId());
mailService.deleteMail(member.getId());
memberRepository.saveAndFlush(member.deleted());

public interface AuthService {
void deleteUser(Member member);
// TODO: 이벀트 기반으둜 κ²Œμ‹œκΈ€ 및 μš”μ²­ 처리
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fullcar.core.config.jwt.JwtTokenProvider;
import com.fullcar.core.exception.NotFoundException;
import com.fullcar.core.exception.UnauthorizedException;
import com.fullcar.core.response.ErrorCode;
import com.fullcar.member.application.member.MemberMapper;
import com.fullcar.member.domain.auth.SocialId;
Expand All @@ -16,7 +17,6 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
Expand Down Expand Up @@ -94,8 +94,7 @@ private void createMember(SocialId socialId, String deviceToken, String refreshT

// νšŒμ› νƒˆν‡΄
public void revoke(Member member) {
RestTemplate restTemplate = new RestTemplateBuilder().build();

RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
headers.set("Authorization", "KakaoAK " + adminKey);
Expand All @@ -106,10 +105,14 @@ public void revoke(Member member) {

HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);

restTemplate.exchange(
KAKAO_UNLINK_ENDPOINT,
HttpMethod.POST,
request,
String.class);
try {
restTemplate.exchange(
KAKAO_UNLINK_ENDPOINT,
HttpMethod.POST,
request,
String.class);
} catch (HttpClientErrorException e) {
throw new UnauthorizedException(ErrorCode.INVALID_KAKAO_USER);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.fullcar.member.domain.auth.SocialId;
import com.fullcar.member.domain.member.Company;
import com.fullcar.member.domain.member.SocialType;
import com.fullcar.member.domain.member.service.MemberIdService;
import com.fullcar.member.domain.member.Member;
import com.fullcar.member.presentation.member.dto.request.OnBoardingRequestDto;
Expand Down Expand Up @@ -59,6 +60,7 @@ public Member toKakaoLoginEntity(SocialId socialId, String deviceToken, String r
.socialId(socialId)
.deviceToken(deviceToken)
.refreshToken(refreshToken)
.socialType(SocialType.KAKAO)
.build();
}

Expand All @@ -69,6 +71,7 @@ public Member toAppleLoginEntity(SocialId socialId, String appleRefreshToken, St
.appleRefreshToken(appleRefreshToken)
.deviceToken(deviceToken)
.refreshToken(refreshToken)
.socialType(SocialType.APPLE)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
@Repository
public interface MailRepository extends JpaRepository<Mail, MailId> {
Mail findByMemberId(MemberId memberId);
boolean existsByMemberId(MemberId memberId);
}
3 changes: 3 additions & 0 deletions src/main/java/com/fullcar/member/domain/member/Member.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ public class Member {

private SocialId socialId;

@Enumerated(EnumType.STRING)
private SocialType socialType;

@Embedded
private Company company;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

@Getter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public enum MemberSocialType {
public enum SocialType {
KAKAO,
APPLE
}
6 changes: 4 additions & 2 deletions src/main/java/com/fullcar/member/infra/MailClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,9 @@ public void checkMailAuthenticationCode(Member member, CodeRequestDto codeReques
@Transactional
@Override
public void deleteMail(MemberId memberId) {
Mail mail = mailRepository.findByMemberId(memberId);
mailRepository.delete(mail);
if (mailRepository.existsByMemberId(memberId)) {
Mail mail = mailRepository.findByMemberId(memberId);
mailRepository.delete(mail);
}
}
}
Loading
Loading