Skip to content

Commit 75dfd83

Browse files
authored
feat: 애플 로그인 API 구현 (#267)
* feat: 외부 API 호출 툴 Feign 설정 * feat: Apple 로그인 구현 + 회원가입 Reqeust Provider 추가
1 parent 4c25f0a commit 75dfd83

File tree

15 files changed

+217
-19
lines changed

15 files changed

+217
-19
lines changed

build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ dependencies {
2525

2626
//외부 API 호출할 때 쓰는 RestTemplate 라이브러리
2727
implementation group: 'org.apache.httpcomponents.client5', name: 'httpclient5', version: '5.2.1'
28+
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:4.1.0'
2829

2930
//S3
3031
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'

src/main/java/com/shallwe/domain/auth/application/AuthService.java

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.shallwe.domain.auth.dto.*;
66
import com.shallwe.domain.auth.exception.AlreadyExistEmailException;
77
import com.shallwe.domain.auth.exception.InvalidPasswordException;
8+
import com.shallwe.domain.auth.exception.UnRegisteredUserException;
89
import com.shallwe.domain.common.Status;
910
import com.shallwe.domain.shopowner.domain.ShopOwner;
1011
import com.shallwe.domain.shopowner.domain.repository.ShopOwnerRepository;
@@ -21,11 +22,14 @@
2122
import com.shallwe.domain.user.domain.User;
2223
import com.shallwe.global.config.security.token.UserPrincipal;
2324
import com.shallwe.global.error.DefaultAuthenticationException;
25+
import com.shallwe.global.infrastructure.feign.apple.AppleClient;
2426
import com.shallwe.global.payload.ErrorCode;
2527
import com.shallwe.global.payload.Message;
2628
import com.shallwe.domain.auth.domain.repository.TokenRepository;
2729
import com.shallwe.domain.user.domain.repository.UserRepository;
2830

31+
import com.shallwe.global.utils.AppleJwtUtils;
32+
import io.jsonwebtoken.Claims;
2933
import lombok.extern.slf4j.Slf4j;
3034
import org.springframework.security.authentication.AuthenticationManager;
3135
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -36,17 +40,18 @@
3640
import org.springframework.transaction.annotation.Transactional;
3741

3842
import lombok.RequiredArgsConstructor;
43+
import org.springframework.web.client.RestTemplate;
3944

4045

41-
@RequiredArgsConstructor
4246
@Service
43-
@Transactional(readOnly = true)
47+
@RequiredArgsConstructor
4448
@Slf4j
49+
@Transactional(readOnly = true)
4550
public class AuthService {
4651

4752
private final CustomTokenProviderService customTokenProviderService;
53+
private final AppleJwtUtils appleJwtUtils;
4854
private final PasswordEncoder passwordEncoder;
49-
private final AuthenticationManager authenticationManager;
5055

5156
private final TokenRepository tokenRepository;
5257
private final UserRepository userRepository;
@@ -59,7 +64,7 @@ public AuthRes signUp(final SignUpReq signUpReq) {
5964

6065
User newUser = User.builder()
6166
.providerId(signUpReq.getProviderId())
62-
.provider(Provider.kakao)
67+
.provider(signUpReq.getProvider())
6368
.name(signUpReq.getNickname())
6469
.email(signUpReq.getEmail())
6570
.profileImgUrl(signUpReq.getProfileImgUrl())
@@ -256,4 +261,36 @@ private boolean valid(final String refreshToken) {
256261
return true;
257262
}
258263

264+
@Transactional
265+
public AuthRes appleSignIn(AppleSignInReq appleSignInReq) {
266+
Claims claims = appleJwtUtils.getClaimsBy(appleSignInReq.getIdentityToken());
267+
Long userId = Long.parseLong(claims.getId());
268+
269+
User user = userRepository.findById(userId).orElseThrow(InvalidUserException::new);
270+
if(user.getName() == null || user.getPhoneNumber() == null || user.getAge() == null || user.getGender() == null) {
271+
throw new UnRegisteredUserException();
272+
}
273+
274+
UserPrincipal userPrincipal = UserPrincipal.createUser(user);
275+
Authentication authentication = new UsernamePasswordAuthenticationToken(
276+
userPrincipal,
277+
null,
278+
userPrincipal.getAuthorities()
279+
);
280+
281+
TokenMapping tokenMapping = customTokenProviderService.createToken(authentication);
282+
Token token = Token.builder()
283+
.refreshToken(tokenMapping.getRefreshToken())
284+
.userEmail(tokenMapping.getUserEmail())
285+
.build();
286+
tokenRepository.save(token);
287+
288+
AuthRes authRes = AuthRes.builder()
289+
.accessToken(tokenMapping.getAccessToken())
290+
.refreshToken(token.getRefreshToken())
291+
.build();
292+
293+
return authRes;
294+
}
295+
259296
}

src/main/java/com/shallwe/domain/auth/application/CustomTokenProviderService.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
import com.shallwe.global.config.security.token.UserPrincipal;
88
import com.shallwe.domain.auth.dto.TokenMapping;
99

10-
import org.springframework.beans.factory.annotation.Autowired;
10+
import com.shallwe.global.infrastructure.feign.apple.AppleClient;
11+
import lombok.RequiredArgsConstructor;
1112
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
1213
import org.springframework.security.core.Authentication;
1314
import org.springframework.security.core.userdetails.UserDetails;
@@ -21,13 +22,12 @@
2122

2223
@Slf4j
2324
@Service
25+
@RequiredArgsConstructor
2426
public class CustomTokenProviderService {
2527

26-
@Autowired
27-
private OAuth2Config oAuth2Config;
28-
29-
@Autowired
30-
private CustomUserDetailsService customUserDetailsService;
28+
private final OAuth2Config oAuth2Config;
29+
private final CustomUserDetailsService customUserDetailsService;
30+
private final AppleClient appleClient;
3131

3232
public TokenMapping refreshToken(Authentication authentication, String refreshToken) {
3333
UserPrincipal userPrincipal = (UserPrincipal) authentication.getPrincipal();
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.shallwe.domain.auth.dto;
2+
3+
import io.swagger.v3.oas.annotations.media.Schema;
4+
import lombok.Data;
5+
6+
@Data
7+
public class AppleSignInReq {
8+
9+
@Schema(type = "string", description = "애플 로그인을 위한 AuthorizationCode")
10+
private String authorizationCode;
11+
12+
@Schema(type = "string", description = "애플 로그인을 위한 IdentityToken")
13+
private String identityToken;
14+
15+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.shallwe.domain.auth.dto;
2+
3+
import lombok.Data;
4+
5+
@Data
6+
public class AppleSignInRes {
7+
8+
private Boolean isSignUpComplete;
9+
10+
}

src/main/java/com/shallwe/domain/auth/dto/SignUpReq.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
package com.shallwe.domain.auth.dto;
22

3+
import com.shallwe.domain.user.domain.Provider;
34
import io.swagger.v3.oas.annotations.media.Schema;
45
import jakarta.validation.constraints.Email;
56
import lombok.Data;
67

78
@Data
89
public class SignUpReq {
910

10-
@Schema( type = "string", example = "123123", description="카카오 고유 유저 ID 입니다.")
11+
@Schema( type = "string", example = "123123", description="카카오/애플 고유 유저 ID 입니다.")
1112
private String providerId;
1213

14+
@Schema( type = "string", example = "KAKAO / APPLE", description="카카오/애플/구글 로그인 제공자 입니다.")
15+
private Provider provider;
16+
1317
@Schema( type = "string", example = "string", description="카카오톡 닉네임 입니다.")
1418
private String nickname;
1519

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.shallwe.domain.auth.exception;
2+
3+
public class UnRegisteredUserException extends RuntimeException {
4+
5+
public UnRegisteredUserException() {
6+
super("회원가입이 완료되지 않은 유저입니다.");
7+
}
8+
9+
}

src/main/java/com/shallwe/domain/auth/presentation/AuthController.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,18 @@ public ResponseCustom<AuthRes> signIn(
5959
return ResponseCustom.OK(authService.signIn(signInReq));
6060
}
6161

62+
@Operation(summary = "애플 로그인", description = "애플 로그인을 수행합니다.")
63+
@ApiResponses(value = {
64+
@ApiResponse(responseCode = "200", description = "애플 로그인 성공", content = { @Content(mediaType = "application/json", schema = @Schema(implementation = AppleSignInRes.class) ) } ),
65+
@ApiResponse(responseCode = "400", description = "애플 로그인 실패", content = { @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class) ) } ),
66+
})
67+
@PostMapping(value="/sign-in/apple")
68+
public ResponseCustom<AuthRes> appleSignIn(
69+
@Parameter(description = "SignInReq Schema를 확인해주세요.", required = true) @RequestBody AppleSignInReq appleSignInReq
70+
) {
71+
return ResponseCustom.OK(authService.appleSignIn(appleSignInReq));
72+
}
73+
6274
@Operation(summary = "토큰 갱신", description = "신규 토큰 갱신을 수행합니다.")
6375
@ApiResponses(value = {
6476
@ApiResponse(responseCode = "200", description = "토큰 갱신 성공", content = { @Content(mediaType = "application/json", schema = @Schema(implementation = AuthRes.class) ) } ),
Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
package com.shallwe.domain.user.domain;
22

33
public enum Provider {
4-
local,
5-
facebook,
6-
google,
7-
github,
8-
kakao,
9-
naver
4+
KAKAO, APPLE, GOOGLE
105
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.shallwe.global.config;
2+
3+
import org.springframework.cloud.openfeign.EnableFeignClients;
4+
import org.springframework.context.annotation.Configuration;
5+
6+
@Configuration
7+
@EnableFeignClients(basePackages = "com.shallwe.global.infrastructure.feign")
8+
public class FeignConfig {
9+
}

0 commit comments

Comments
 (0)