diff --git a/src/common-module/src/main/proto/send_email_auth.proto b/src/common-module/src/main/proto/send_email_auth.proto index e6950503..07454818 100644 --- a/src/common-module/src/main/proto/send_email_auth.proto +++ b/src/common-module/src/main/proto/send_email_auth.proto @@ -8,9 +8,7 @@ service GAuthService { } message GSendEmailAuthRequest { - int64 id = 1; - string email = 2; - string nickname = 3; + string email = 1; } message GSendEmailAuthResponse { diff --git a/src/common-module/src/main/proto/update_user_auth-status.proto b/src/common-module/src/main/proto/update_user_auth-status.proto new file mode 100644 index 00000000..2f8716d4 --- /dev/null +++ b/src/common-module/src/main/proto/update_user_auth-status.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.palette.grpc"; + +service GUserService { + rpc updateUserAuthStatus (GUpdateUserAuthStatusRequest) returns (GUpdateUserAuthStatusResponse) {} +} + +message GUpdateUserAuthStatusRequest { + string email = 1; +} + +message GUpdateUserAuthStatusResponse { + bool message = 1; +} diff --git a/src/user-service/build.gradle.kts b/src/user-service/build.gradle.kts index 0df95d8a..240021ee 100644 --- a/src/user-service/build.gradle.kts +++ b/src/user-service/build.gradle.kts @@ -24,7 +24,7 @@ repositories { extra["springCloudVersion"] = "2023.0.0" dependencies { - implementation ("net.devh:grpc-spring-boot-starter:2.15.0.RELEASE") + implementation("net.devh:grpc-spring-boot-starter:2.15.0.RELEASE") implementation(project(":common-module")) implementation("org.springframework.boot:spring-boot-starter-web") diff --git a/src/user-service/src/main/java/org/palette/easeluserservice/common/PasswordUtilizer.java b/src/user-service/src/main/java/org/palette/easeluserservice/common/PasswordUtilizer.java new file mode 100644 index 00000000..a3c04ddf --- /dev/null +++ b/src/user-service/src/main/java/org/palette/easeluserservice/common/PasswordUtilizer.java @@ -0,0 +1,16 @@ +package org.palette.easeluserservice.common; + +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + +public class PasswordUtilizer { + + private static final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); + + public static String hashPassword(String password) { + return encoder.encode(password); + } + + public static boolean checkPassword(String rawPassword, String encodedPassword) { + return encoder.matches(rawPassword, encodedPassword); + } +} diff --git a/src/user-service/src/main/java/org/palette/easeluserservice/config/ApplicationConfig.java b/src/user-service/src/main/java/org/palette/easeluserservice/config/ApplicationConfig.java index a7cd3785..b6fa0100 100644 --- a/src/user-service/src/main/java/org/palette/easeluserservice/config/ApplicationConfig.java +++ b/src/user-service/src/main/java/org/palette/easeluserservice/config/ApplicationConfig.java @@ -1,18 +1,13 @@ package org.palette.easeluserservice.config; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; -import org.springframework.context.annotation.Bean; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; import org.springframework.scheduling.annotation.EnableAsync; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @EnableDiscoveryClient @EnableJpaAuditing @EnableAsync public class ApplicationConfig { - @Bean - public static BCryptPasswordEncoder bCryptPasswordEncoder() { - return new BCryptPasswordEncoder(); - } + } diff --git a/src/user-service/src/main/java/org/palette/easeluserservice/exception/ExceptionType.java b/src/user-service/src/main/java/org/palette/easeluserservice/exception/ExceptionType.java index 7a540dac..30f0f846 100644 --- a/src/user-service/src/main/java/org/palette/easeluserservice/exception/ExceptionType.java +++ b/src/user-service/src/main/java/org/palette/easeluserservice/exception/ExceptionType.java @@ -9,66 +9,59 @@ public enum ExceptionType { // 400 - USER_000001( - "USER_000001", + USER_400_000001( + "USER_400_000001", "INCORRECT_PARAMETER", "요청 파라미터가 올바르지 않습니다.", HttpStatus.BAD_REQUEST ), // 401 - USER_000002( - "USER_000002", + USER_401_000001( + "USER_401_000001", "MISSED AUTHENTICATION", "해당 요청은 인증이 필요합니다.", HttpStatus.UNAUTHORIZED ), // 403 - USER_000003( - "USER_000003", + USER_403_000001( + "USER_403_000001", "NOT ALLOWED PERMISSION", "해당 요청에 대한 권한이 없습니다.", HttpStatus.FORBIDDEN ), - // 404 - USER_000004( - "USER_000004", + USER_404_000001( + "USER_404_000001", "NOT FOUNDED", "해당 리소스가 존재하지 않습니다.", HttpStatus.NOT_FOUND ), // 405 - USER_000005( - "USER_000005", + USER_405_000001( + "USER_403_000005", "NOT ALLOWED METHOD", "올바르지 않은 요청 메서드입니다.", HttpStatus.METHOD_NOT_ALLOWED ), // 409 - USER_000006( - "USER_000006", + USER_409_000001( + "USER_409_000001", "DUPLICATED", "중복된 리소스가 있습니다.", HttpStatus.CONFLICT ), - USER_000007( - "USER_000007", - "BROKEN_TOKEN", - "요청 토큰이 올바르지 않습니다.", - HttpStatus.BAD_REQUEST - ), - - USER_000008( - "USER_000008", - "EXPIRED_TOKEN", - "요청 토큰이 만료되었습니다.", - HttpStatus.FORBIDDEN + // 500 + USER_500_000001( + "AUTH_500_000001", + "INTERNAL SERVER ERROR", + "서버 간 통신 중 예기치 못한 오류가 발생했습니다.", + HttpStatus.INTERNAL_SERVER_ERROR ), ; diff --git a/src/user-service/src/main/java/org/palette/easeluserservice/exception/GlobalExceptionHandler.java b/src/user-service/src/main/java/org/palette/easeluserservice/exception/GlobalExceptionHandler.java index e099c08e..ec59135e 100644 --- a/src/user-service/src/main/java/org/palette/easeluserservice/exception/GlobalExceptionHandler.java +++ b/src/user-service/src/main/java/org/palette/easeluserservice/exception/GlobalExceptionHandler.java @@ -17,7 +17,7 @@ public class GlobalExceptionHandler { MethodArgumentTypeMismatchException.class, }) public ResponseEntity handleRequestValidationException(Exception e) { - ExceptionType exceptionType = ExceptionType.USER_000001; + ExceptionType exceptionType = ExceptionType.USER_404_000001; ExceptionResponse exceptionResponse = ExceptionResponse.builder() .code(exceptionType.getCode()) .message(exceptionType.getMessage()) diff --git a/src/user-service/src/main/java/org/palette/easeluserservice/external/GrpcAuth.java b/src/user-service/src/main/java/org/palette/easeluserservice/external/GrpcAuthClient.java similarity index 57% rename from src/user-service/src/main/java/org/palette/easeluserservice/external/GrpcAuth.java rename to src/user-service/src/main/java/org/palette/easeluserservice/external/GrpcAuthClient.java index d539b54c..796783a8 100644 --- a/src/user-service/src/main/java/org/palette/easeluserservice/external/GrpcAuth.java +++ b/src/user-service/src/main/java/org/palette/easeluserservice/external/GrpcAuthClient.java @@ -1,34 +1,29 @@ package org.palette.easeluserservice.external; import io.grpc.StatusRuntimeException; -import lombok.RequiredArgsConstructor; import net.devh.boot.grpc.client.inject.GrpcClient; +import org.palette.easeluserservice.exception.BaseException; +import org.palette.easeluserservice.exception.ExceptionType; import org.palette.easeluserservice.persistence.User; import org.palette.grpc.GAuthServiceGrpc; import org.palette.grpc.GSendEmailAuthRequest; -import org.palette.grpc.GSendEmailAuthResponse; import org.springframework.stereotype.Component; @Component -@RequiredArgsConstructor -public class GrpcAuth { +public class GrpcAuthClient { @GrpcClient("auth-service") private GAuthServiceGrpc.GAuthServiceBlockingStub gAuthServiceBlockingStub; - public GSendEmailAuthResponse sendEmailAuth(User user) { - // TODO: 매개변수 및 반환값 변경, 예외처리 + public void sendEmailAuth(User user) { try { - return gAuthServiceBlockingStub.sendEmailAuth( + gAuthServiceBlockingStub.sendEmailAuth( GSendEmailAuthRequest.newBuilder() - .setId(user.getId()) .setEmail(user.getEmail()) - .setNickname(user.getProfile().nickname()) .build() ); } catch (final StatusRuntimeException e) { - System.out.println(e.getMessage()); - return null; + throw new BaseException(ExceptionType.USER_500_000001); } } } diff --git a/src/user-service/src/main/java/org/palette/easeluserservice/external/GrpcServerByAuthService.java b/src/user-service/src/main/java/org/palette/easeluserservice/external/GrpcServerByAuthService.java new file mode 100644 index 00000000..d6522cd9 --- /dev/null +++ b/src/user-service/src/main/java/org/palette/easeluserservice/external/GrpcServerByAuthService.java @@ -0,0 +1,35 @@ +package org.palette.easeluserservice.external; + +import io.grpc.stub.StreamObserver; +import lombok.RequiredArgsConstructor; +import net.devh.boot.grpc.server.service.GrpcService; +import org.palette.easeluserservice.persistence.User; +import org.palette.easeluserservice.service.UserService; +import org.palette.grpc.GUpdateUserAuthStatusRequest; +import org.palette.grpc.GUpdateUserAuthStatusResponse; +import org.palette.grpc.GUserServiceGrpc; +import org.springframework.transaction.annotation.Transactional; + +@GrpcService +@RequiredArgsConstructor +public class GrpcServerByAuthService extends GUserServiceGrpc.GUserServiceImplBase { + + private final UserService userService; + + @Transactional + @Override + public void updateUserAuthStatus( + GUpdateUserAuthStatusRequest request, + StreamObserver responseObserver + ) { + User user = userService.loadByEmail(request.getEmail()); + + userService.updateUserAuthStatus(user); + + GUpdateUserAuthStatusResponse response = GUpdateUserAuthStatusResponse.newBuilder() + .setMessage(true) + .build(); + responseObserver.onNext(response); + responseObserver.onCompleted(); + } +} diff --git a/src/user-service/src/main/java/org/palette/easeluserservice/external/GrpcSocial.java b/src/user-service/src/main/java/org/palette/easeluserservice/external/GrpcSocialClient.java similarity index 83% rename from src/user-service/src/main/java/org/palette/easeluserservice/external/GrpcSocial.java rename to src/user-service/src/main/java/org/palette/easeluserservice/external/GrpcSocialClient.java index 4977b5ba..7e7ba6c8 100644 --- a/src/user-service/src/main/java/org/palette/easeluserservice/external/GrpcSocial.java +++ b/src/user-service/src/main/java/org/palette/easeluserservice/external/GrpcSocialClient.java @@ -2,6 +2,8 @@ import io.grpc.StatusRuntimeException; import net.devh.boot.grpc.client.inject.GrpcClient; +import org.palette.easeluserservice.exception.BaseException; +import org.palette.easeluserservice.exception.ExceptionType; import org.palette.easeluserservice.persistence.User; import org.palette.grpc.GCreateUserRequest; import org.palette.grpc.GCreateUserResponse; @@ -9,13 +11,12 @@ import org.springframework.stereotype.Component; @Component -public class GrpcSocial { +public class GrpcSocialClient { @GrpcClient("social-service") private GSocialServiceGrpc.GSocialServiceBlockingStub gSocialServiceBlockingStub; public GCreateUserResponse createSocialUser(User user) { - // TODO: 매개변수 및 반환값 변경, 예외처리 try { return gSocialServiceBlockingStub.createUser( GCreateUserRequest.newBuilder() @@ -26,8 +27,7 @@ public GCreateUserResponse createSocialUser(User user) { .setIsActive(user.getIsActivated()) .build()); } catch (final StatusRuntimeException e) { - System.out.println(e.getMessage()); - return null; + throw new BaseException(ExceptionType.USER_500_000001); } } } diff --git a/src/user-service/src/main/java/org/palette/easeluserservice/persistence/User.java b/src/user-service/src/main/java/org/palette/easeluserservice/persistence/User.java index 20d058af..ba78ced2 100644 --- a/src/user-service/src/main/java/org/palette/easeluserservice/persistence/User.java +++ b/src/user-service/src/main/java/org/palette/easeluserservice/persistence/User.java @@ -65,6 +65,10 @@ public class User { @Column(name = "deleted_at") private LocalDateTime deletedAt = null; + public void updateToAuthed() { + this.authed = true; + } + public Boolean isUserNotAuthed() { return !this.getAuthed(); } diff --git a/src/user-service/src/main/java/org/palette/easeluserservice/persistence/embed/Password.java b/src/user-service/src/main/java/org/palette/easeluserservice/persistence/embed/Password.java index ddd5de21..0c7405d8 100644 --- a/src/user-service/src/main/java/org/palette/easeluserservice/persistence/embed/Password.java +++ b/src/user-service/src/main/java/org/palette/easeluserservice/persistence/embed/Password.java @@ -2,8 +2,7 @@ import jakarta.persistence.Column; import jakarta.persistence.Embeddable; - -import static org.palette.easeluserservice.config.ApplicationConfig.bCryptPasswordEncoder; +import org.palette.easeluserservice.common.PasswordUtilizer; @Embeddable public record Password( @@ -11,6 +10,6 @@ public record Password( String value ) { public Password(String value) { - this.value = bCryptPasswordEncoder().encode(value); + this.value = PasswordUtilizer.hashPassword(value); } } diff --git a/src/user-service/src/main/java/org/palette/easeluserservice/service/UserService.java b/src/user-service/src/main/java/org/palette/easeluserservice/service/UserService.java index 58609f13..f0b38603 100644 --- a/src/user-service/src/main/java/org/palette/easeluserservice/service/UserService.java +++ b/src/user-service/src/main/java/org/palette/easeluserservice/service/UserService.java @@ -66,15 +66,25 @@ public User createCompletedUser( return user; } + public void updateUserAuthStatus(User user) { + user.updateToAuthed(); + } + public void isEmailAlreadyExists(String requestedEmail) { - if (userJpaRepository.existsByEmail(requestedEmail)) throw new BaseException(ExceptionType.USER_000006); + if (userJpaRepository.existsByEmail(requestedEmail)) { + throw new BaseException(ExceptionType.USER_409_000001); + } } public void isUsernameAlreadyExists(String requestedUsername) { - if (userJpaRepository.existsByUsername(requestedUsername)) throw new BaseException(ExceptionType.USER_000006); + if (userJpaRepository.existsByUsername(requestedUsername)) { + throw new BaseException(ExceptionType.USER_409_000001); + } } - public Optional loadByEmail(String email) { - return userJpaRepository.findByEmail(email); + public User loadByEmail(String email) { + return userJpaRepository.findByEmail(email).orElseThrow(() -> + new BaseException(ExceptionType.USER_404_000001) + ); } } diff --git a/src/user-service/src/main/java/org/palette/easeluserservice/usecase/UserUsecase.java b/src/user-service/src/main/java/org/palette/easeluserservice/usecase/UserUsecase.java index e5360990..26555d03 100644 --- a/src/user-service/src/main/java/org/palette/easeluserservice/usecase/UserUsecase.java +++ b/src/user-service/src/main/java/org/palette/easeluserservice/usecase/UserUsecase.java @@ -6,23 +6,21 @@ import org.palette.easeluserservice.dto.response.EmailDuplicationVerifyResponse; import org.palette.easeluserservice.exception.BaseException; import org.palette.easeluserservice.exception.ExceptionType; -import org.palette.easeluserservice.external.GrpcAuth; -import org.palette.easeluserservice.external.GrpcSocial; +import org.palette.easeluserservice.external.GrpcAuthClient; +import org.palette.easeluserservice.external.GrpcSocialClient; import org.palette.easeluserservice.persistence.User; import org.palette.easeluserservice.service.UserService; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.Optional; - @RequiredArgsConstructor @Service @Transactional(readOnly = true) public class UserUsecase { private final UserService userService; - private final GrpcSocial gRPCSocial; - private final GrpcAuth gRPCAuth; + private final GrpcSocialClient gRPCSocialClient; + private final GrpcAuthClient gRPCAuthClient; public EmailDuplicationVerifyResponse executeNicknameDuplicationVerify( String email @@ -42,18 +40,15 @@ public void executeTemporaryJoin( temporaryJoinRequest.nickname() ); -// gRPCSendEmailAuth(user); + gRPCAuthClient.sendEmailAuth(user); } @Transactional public void executeJoin( JoinRequest joinRequest ) { - final Optional optionalUser = userService.loadByEmail( - joinRequest.email() - ); - - User user = validateJoinRequest(joinRequest, optionalUser); + User user = userService.loadByEmail(joinRequest.email()); + validateJoinRequest(joinRequest, user); user = userService.createCompletedUser( user, @@ -65,22 +60,13 @@ public void executeJoin( joinRequest.websitePath() ); - gRPCCreateSocialUser(user); - } - - private void gRPCSendEmailAuth(User user) { - gRPCAuth.sendEmailAuth(user); - } - - private void gRPCCreateSocialUser(User user) { - gRPCSocial.createSocialUser(user); + gRPCSocialClient.createSocialUser(user); } - private User validateJoinRequest(JoinRequest joinRequest, Optional optionalUser) { - if (optionalUser.isEmpty()) throw new BaseException(ExceptionType.USER_000004); - User user = optionalUser.get(); - if (user.isUserNotAuthed()) throw new BaseException(ExceptionType.USER_000002); + private void validateJoinRequest(JoinRequest joinRequest, User user) { + if (user.isUserNotAuthed()) { + throw new BaseException(ExceptionType.USER_401_000001); + } userService.isUsernameAlreadyExists(joinRequest.username()); - return user; } } diff --git a/src/user-service/src/main/resources/application.yml b/src/user-service/src/main/resources/application.yml index bb7eb895..cd9eb8ca 100644 --- a/src/user-service/src/main/resources/application.yml +++ b/src/user-service/src/main/resources/application.yml @@ -1,5 +1,5 @@ server: - port: 10002 + port: 10003 spring: application: @@ -26,14 +26,19 @@ eureka: fetch-registry: true register-with-eureka: true service-url: - defaultZone: http://localhost:8761/eureka + defaultZone: http://host.docker.internal:8761/eureka grpc: server: - port: 11002 + port: 11003 client: social-service: address: 'discovery:///SOCIAL-SERVICE' enableKeepAlive: true keepAliveWithoutCalls: true negotiationType: plaintext + auth-service: + address: 'discovery:///AUTH-SERVICE' + enableKeepAlive: true + keepAliveWithoutCalls: true + negotiationType: plaintext diff --git a/src/user-service/src/test/java/org/palette/easeluserservice/e2e/api/Join.java b/src/user-service/src/test/java/org/palette/easeluserservice/e2e/api/Join.java index 67af3dcd..7700d4b9 100644 --- a/src/user-service/src/test/java/org/palette/easeluserservice/e2e/api/Join.java +++ b/src/user-service/src/test/java/org/palette/easeluserservice/e2e/api/Join.java @@ -82,7 +82,6 @@ public void insertTemporaryUser() throws NoSuchMethodException, @Test @DisplayName("회원가입 정상 로직 테스트") void executePassCase() throws Exception { - System.out.println("userJpaRepository.findByEmail(\"diger@gmail.com\") = " + userJpaRepository.findByEmail("diger@gmail.com")); JoinRequest joinRequest = new JoinRequest( "diger@gmail.com", "digerPassword", diff --git a/src/user-service/src/test/java/org/palette/easeluserservice/e2e/api/TemporaryJoin.java b/src/user-service/src/test/java/org/palette/easeluserservice/e2e/api/TemporaryJoin.java index 72023810..68bc6d1a 100644 --- a/src/user-service/src/test/java/org/palette/easeluserservice/e2e/api/TemporaryJoin.java +++ b/src/user-service/src/test/java/org/palette/easeluserservice/e2e/api/TemporaryJoin.java @@ -7,13 +7,13 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -public class TemporaryJoin extends AcceptanceTestBase { +class TemporaryJoin extends AcceptanceTestBase { @Test @DisplayName("임시 회원가입 정상 로직 테스트") - public void executePassCase() throws Exception { + void executePassCase() throws Exception { TemporaryJoinRequest temporaryJoinRequest = new TemporaryJoinRequest( - "diger@gmail.com", + "kitten.diger@gmail.com", "digerDisplayName" ); executePost(