package com.sb.web.auth.controller; import com.sb.web.auth.dto.LoginRequest; import com.sb.web.auth.dto.LoginResponse; import com.sb.web.auth.dto.MemberResponse; import com.sb.web.auth.dto.PasswordChangeRequest; import com.sb.web.auth.dto.SessionUser; import com.sb.web.auth.dto.SignupRequest; import com.sb.web.auth.service.AuthService; import com.sb.web.auth.web.AuthInterceptor; import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; /** * 인증 API. * POST /api/auth/signup 회원가입 (비보호) * POST /api/auth/login 로그인 (비보호) * POST /api/auth/logout 로그아웃 (보호) * GET /api/auth/me 내 정보 (보호) */ @RestController @RequestMapping("/api/auth") @RequiredArgsConstructor public class AuthController { private final AuthService authService; private final com.sb.web.admin.service.AppSettingService appSettingService; /** 회원가입 허용 여부 (비보호) — 프론트가 가입 진입 전에 차단 표시용 */ @GetMapping("/signup-enabled") public java.util.Map signupEnabled() { return java.util.Map.of("enabled", appSettingService.isSignupEnabled()); } @PostMapping("/signup") public ResponseEntity signup(@Valid @RequestBody SignupRequest req, HttpServletRequest request) { return ResponseEntity.status(HttpStatus.CREATED).body(authService.signup(req, clientIp(request))); } /** 클라이언트 IP (nginx 프록시 뒤 → X-Forwarded-For 우선) */ private String clientIp(HttpServletRequest request) { String xff = request.getHeader("X-Forwarded-For"); if (xff != null && !xff.isBlank()) { return xff.split(",")[0].trim(); } return request.getRemoteAddr(); } @PostMapping("/login") public LoginResponse login(@Valid @RequestBody LoginRequest req, HttpServletRequest request) { return authService.login(req, clientIp(request)); } /** 구글 OAuth 클라이언트 ID (비보호) — 프론트가 구글 버튼 노출/초기화에 사용. 미설정 시 빈 문자열 */ @GetMapping("/google-client-id") public java.util.Map googleClientId() { return java.util.Map.of("clientId", authService.googleClientId()); } /** 구글 로그인/가입 (비보호) — ID 토큰 검증 후 세션 발급 */ @PostMapping("/google") public LoginResponse googleLogin(@Valid @RequestBody com.sb.web.auth.dto.GoogleLoginRequest req) { return authService.googleLogin(req.getIdToken(), req.isRememberMe()); } @PostMapping("/logout") public ResponseEntity logout(HttpServletRequest request) { authService.logout(AuthInterceptor.resolveToken(request)); return ResponseEntity.noContent().build(); } @GetMapping("/me") public SessionUser me(@RequestAttribute(AuthInterceptor.CURRENT_MEMBER) SessionUser current) { return current; } @PutMapping("/password") public ResponseEntity changePassword( @Valid @RequestBody PasswordChangeRequest req, @RequestAttribute(AuthInterceptor.CURRENT_MEMBER) SessionUser current) { authService.changePassword(current.getId(), req); return ResponseEntity.noContent().build(); } /** 가입정보 변경 진입 전 비밀번호 재인증 */ @PostMapping("/verify-password") public ResponseEntity verifyPassword( @Valid @RequestBody com.sb.web.auth.dto.PasswordVerifyRequest req, @RequestAttribute(AuthInterceptor.CURRENT_MEMBER) SessionUser current) { authService.verifyPassword(current.getId(), req.getPassword()); return ResponseEntity.noContent().build(); } /** 가입정보(이름/이메일) 변경 */ @PutMapping("/profile") public MemberResponse updateProfile( @Valid @RequestBody com.sb.web.auth.dto.ProfileUpdateRequest req, @RequestAttribute(AuthInterceptor.CURRENT_MEMBER) SessionUser current, HttpServletRequest request) { return authService.updateProfile(current.getId(), AuthInterceptor.resolveToken(request), req); } }