diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/auth/controller/AuthController.java b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/controller/AuthController.java new file mode 100644 index 00000000..1e2f9dae --- /dev/null +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/controller/AuthController.java @@ -0,0 +1,50 @@ +package com.gltkorea.icebang.auth.controller; + +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.Authentication; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.gltkorea.icebang.auth.dto.DefaultRequestWrapper; +import com.gltkorea.icebang.auth.dto.LoginDto; +import com.gltkorea.icebang.auth.dto.SignUpDto; +import com.gltkorea.icebang.auth.provider.AuthProvider; +import com.gltkorea.icebang.auth.provider.AuthProviderFactory; + +import lombok.RequiredArgsConstructor; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/v0/auth") +public class AuthController { + private final AuthProviderFactory authProviderFactory; + + @PostMapping("/signup") + public ResponseEntity signUp(@RequestBody SignUpDto signUpDto) { + // 1. Wrapper DTO 생성 + DefaultRequestWrapper wrapper = DefaultRequestWrapper.builder().signUpDto(signUpDto).build(); + + // 2. Factory에서 Provider 선택 + @SuppressWarnings("unchecked") + AuthProvider provider = + (AuthProvider) authProviderFactory.getProvider("default"); + + // 3. Provider에 인증 위임 (Provider 내부에서 signUp + login 처리) + Authentication auth = provider.authenticate(wrapper); + + // 4. 결과 반환 + return ResponseEntity.status(201).body(auth); + } + + @PostMapping("/signin") + public ResponseEntity signIn(@RequestBody LoginDto loginDto) { + DefaultRequestWrapper wrapper = DefaultRequestWrapper.builder().loginDto(loginDto).build(); + @SuppressWarnings("unchecked") + AuthProvider provider = + (AuthProvider) authProviderFactory.getProvider("default"); + Authentication auth = provider.authenticate(wrapper); + return ResponseEntity.ok(auth); + } +} diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/auth/controller/Oauth2CallbackController.java b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/controller/Oauth2CallbackController.java new file mode 100644 index 00000000..f21d206a --- /dev/null +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/controller/Oauth2CallbackController.java @@ -0,0 +1,20 @@ +package com.gltkorea.icebang.auth.controller; + +import org.springframework.web.bind.annotation.*; + +import lombok.RequiredArgsConstructor; + +@RestController +@RequestMapping("/v0/oauth2/callback") +@RequiredArgsConstructor +public class Oauth2CallbackController { + + @GetMapping("/kakao") + public void handleKakaoCallback(@RequestParam String code) { + // OAuth2RequestWrapper wrapper = new OAuth2RequestWrapper(new + // Oauth2CallbackContent("kakao", code)); + // OAuth2AuthProvider provider = (OAuth2AuthProvider) + // authProviderFactory.getProvider(providerKey); + // Authentication auth = provider.authenticate(wrapper); + } +} diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/auth/dto/AuthRequestWrapper.java b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/dto/AuthRequestWrapper.java new file mode 100644 index 00000000..3aac5ee4 --- /dev/null +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/dto/AuthRequestWrapper.java @@ -0,0 +1,3 @@ +package com.gltkorea.icebang.auth.dto; + +public interface AuthRequestWrapper {} diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/auth/dto/DefaultRequestWrapper.java b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/dto/DefaultRequestWrapper.java new file mode 100644 index 00000000..4c2ebc93 --- /dev/null +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/dto/DefaultRequestWrapper.java @@ -0,0 +1,13 @@ +package com.gltkorea.icebang.auth.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; + +@Builder +@AllArgsConstructor +@Getter +public class DefaultRequestWrapper implements AuthRequestWrapper { + private final LoginDto loginDto; + private final SignUpDto signUpDto; +} diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/auth/dto/LoginDto.java b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/dto/LoginDto.java new file mode 100644 index 00000000..73fda179 --- /dev/null +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/dto/LoginDto.java @@ -0,0 +1,3 @@ +package com.gltkorea.icebang.auth.dto; + +public class LoginDto {} diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/auth/dto/OAuth2RequestWrapper.java b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/dto/OAuth2RequestWrapper.java new file mode 100644 index 00000000..86e9b5d7 --- /dev/null +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/dto/OAuth2RequestWrapper.java @@ -0,0 +1,12 @@ +package com.gltkorea.icebang.auth.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +@AllArgsConstructor +public class OAuth2RequestWrapper implements AuthRequestWrapper { + private Oauth2CallbackContent callbackContent; +} diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/auth/dto/Oauth2CallbackContent.java b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/dto/Oauth2CallbackContent.java new file mode 100644 index 00000000..d496b534 --- /dev/null +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/dto/Oauth2CallbackContent.java @@ -0,0 +1,7 @@ +package com.gltkorea.icebang.auth.dto; + +public class Oauth2CallbackContent { + private String code; + private String state; + private String provider; +} diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/auth/dto/SignUpDto.java b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/dto/SignUpDto.java new file mode 100644 index 00000000..5dc869fa --- /dev/null +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/dto/SignUpDto.java @@ -0,0 +1,3 @@ +package com.gltkorea.icebang.auth.dto; + +public class SignUpDto {} diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/auth/provider/AuthProvider.java b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/provider/AuthProvider.java new file mode 100644 index 00000000..8380e96e --- /dev/null +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/provider/AuthProvider.java @@ -0,0 +1,11 @@ +package com.gltkorea.icebang.auth.provider; + +import org.springframework.security.core.Authentication; + +import com.gltkorea.icebang.auth.dto.AuthRequestWrapper; + +public interface AuthProvider { + boolean supports(T request); + + Authentication authenticate(T request); +} diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/auth/provider/AuthProviderFactory.java b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/provider/AuthProviderFactory.java new file mode 100644 index 00000000..4f41363e --- /dev/null +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/provider/AuthProviderFactory.java @@ -0,0 +1,44 @@ +package com.gltkorea.icebang.auth.provider; + +import java.util.Map; + +import org.springframework.stereotype.Component; + +import com.gltkorea.icebang.auth.dto.AuthRequestWrapper; + +import lombok.RequiredArgsConstructor; + +@Component +@RequiredArgsConstructor +public class AuthProviderFactory { + + private final Map> providers; + + /** + * providerKey에 해당하는 AuthProvider 반환 + * + * @param providerKey "google", "naver", "default" 등, enum으로 refactoring 필요 + * @return AuthProvider + */ + public AuthProvider getProvider(String providerKey) { + AuthProvider provider = providers.get(providerKey.toLowerCase()); + if (provider == null) { + throw new IllegalArgumentException("Unknown auth provider: " + providerKey); + } + return provider; + } + + /** + * OAuth2 전용 Provider 반환 + * + * @param providerKey OAuth2 provider key + * @return OAuth2AuthProvider + */ + public OAuth2AuthProvider getOAuth2Provider(String providerKey) { + AuthProvider provider = getProvider(providerKey); + if (!(provider instanceof OAuth2AuthProvider oauthProvider)) { + throw new IllegalArgumentException(providerKey + " is not an OAuth2 provider"); + } + return oauthProvider; + } +} diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/auth/provider/DefaultProvider.java b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/provider/DefaultProvider.java new file mode 100644 index 00000000..40a44c7c --- /dev/null +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/provider/DefaultProvider.java @@ -0,0 +1,19 @@ +package com.gltkorea.icebang.auth.provider; + +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Component; + +import com.gltkorea.icebang.auth.dto.DefaultRequestWrapper; + +@Component("default") +public class DefaultProvider implements AuthProvider { + @Override + public boolean supports(DefaultRequestWrapper request) { + return false; + } + + @Override + public Authentication authenticate(DefaultRequestWrapper request) { + return null; + } +} diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/auth/provider/OAuth2AuthProvider.java b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/provider/OAuth2AuthProvider.java new file mode 100644 index 00000000..30be51f4 --- /dev/null +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/provider/OAuth2AuthProvider.java @@ -0,0 +1,9 @@ +package com.gltkorea.icebang.auth.provider; + +import org.springframework.security.core.Authentication; + +import com.gltkorea.icebang.auth.dto.OAuth2RequestWrapper; + +public interface OAuth2AuthProvider extends AuthProvider { + Authentication authenticateWithCode(OAuth2RequestWrapper oauthContent); +} diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/auth/service/AuthService.java b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/service/AuthService.java new file mode 100644 index 00000000..30a2a131 --- /dev/null +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/service/AuthService.java @@ -0,0 +1,13 @@ +package com.gltkorea.icebang.auth.service; + +import com.gltkorea.icebang.auth.dto.LoginDto; +import com.gltkorea.icebang.auth.dto.SignUpDto; +import com.gltkorea.icebang.domain.user.model.Users; + +public interface AuthService { + Users signUp(SignUpDto signUpDto); + + Users login(LoginDto loginDto); + + Users loadUser(String identifier); +} diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/auth/service/AuthServiceImpl.java b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/service/AuthServiceImpl.java new file mode 100644 index 00000000..aa118d2d --- /dev/null +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/service/AuthServiceImpl.java @@ -0,0 +1,25 @@ +package com.gltkorea.icebang.auth.service; + +import org.springframework.stereotype.Service; + +import com.gltkorea.icebang.auth.dto.LoginDto; +import com.gltkorea.icebang.auth.dto.SignUpDto; +import com.gltkorea.icebang.domain.user.model.Users; + +@Service +public class AuthServiceImpl implements AuthService { + @Override + public Users signUp(SignUpDto signUpDto) { + return null; + } + + @Override + public Users login(LoginDto loginDto) { + return null; + } + + @Override + public Users loadUser(String identifier) { + return null; + } +} diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/auth/service/state/AuthStateService.java b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/service/state/AuthStateService.java new file mode 100644 index 00000000..c802b309 --- /dev/null +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/service/state/AuthStateService.java @@ -0,0 +1,9 @@ +package com.gltkorea.icebang.auth.service.state; + +import org.springframework.security.core.userdetails.UserDetails; + +public sealed interface AuthStateService permits SessionStateService, JwtTokenStateService { + String create(UserDetails userDetails); + + UserDetails validate(String identifier); +} diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/auth/service/state/JwtTokenStateService.java b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/service/state/JwtTokenStateService.java new file mode 100644 index 00000000..9065820e --- /dev/null +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/service/state/JwtTokenStateService.java @@ -0,0 +1,15 @@ +package com.gltkorea.icebang.auth.service.state; + +import org.springframework.security.core.userdetails.UserDetails; + +public final class JwtTokenStateService implements AuthStateService { + @Override + public String create(UserDetails userDetails) { + return ""; + } + + @Override + public UserDetails validate(String identifier) { + return null; + } +} diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/auth/service/state/SessionStateService.java b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/service/state/SessionStateService.java new file mode 100644 index 00000000..9bed4d1a --- /dev/null +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/auth/service/state/SessionStateService.java @@ -0,0 +1,15 @@ +package com.gltkorea.icebang.auth.service.state; + +import org.springframework.security.core.userdetails.UserDetails; + +public final class SessionStateService implements AuthStateService { + @Override + public String create(UserDetails userDetails) { + return ""; + } + + @Override + public UserDetails validate(String identifier) { + return null; + } +} diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/domain/user/UserStatus.java b/apps/user-service/src/main/java/com/gltkorea/icebang/domain/user/UserStatus.java new file mode 100644 index 00000000..b23e47e8 --- /dev/null +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/domain/user/UserStatus.java @@ -0,0 +1,8 @@ +package com.gltkorea.icebang.domain.user; + +public enum UserStatus { + ONBOARDING, // email, password만 된 경우 + ACTIVE, // 완전히 활성화됨 + SUSPENDED, // 일시 정지 + DELETED // 삭제됨 +} diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/domain/user/model/Users.java b/apps/user-service/src/main/java/com/gltkorea/icebang/domain/user/model/Users.java new file mode 100644 index 00000000..ab4d28d1 --- /dev/null +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/domain/user/model/Users.java @@ -0,0 +1,7 @@ +package com.gltkorea.icebang.domain.user.model; + +import com.gltkorea.icebang.domain.user.UserStatus; + +public class Users { + private UserStatus status; +} diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/domain/user/service/UserAuthServiceImpl.java b/apps/user-service/src/main/java/com/gltkorea/icebang/domain/user/service/SecurityAuthenticateAdapter.java similarity index 52% rename from apps/user-service/src/main/java/com/gltkorea/icebang/domain/user/service/UserAuthServiceImpl.java rename to apps/user-service/src/main/java/com/gltkorea/icebang/domain/user/service/SecurityAuthenticateAdapter.java index 272e289e..f33f546f 100644 --- a/apps/user-service/src/main/java/com/gltkorea/icebang/domain/user/service/UserAuthServiceImpl.java +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/domain/user/service/SecurityAuthenticateAdapter.java @@ -3,11 +3,16 @@ import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; +import com.gltkorea.icebang.auth.service.AuthService; import com.gltkorea.icebang.domain.user.model.UserAccountPrincipal; +import com.gltkorea.icebang.domain.user.model.Users; + +public class SecurityAuthenticateAdapter implements UserAuthService { + private AuthService authService; -public class UserAuthServiceImpl implements UserAuthService { @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { - return UserAccountPrincipal.builder().build(); + Users user = authService.loadUser(username); + return UserAccountPrincipal.builder().build(); // @TODO users -> userdetail로 } }