105 lines
4.8 KiB
Java
105 lines
4.8 KiB
Java
package com.zioinfo.mes.auth;
|
|
|
|
import com.zioinfo.mes.auth.dto.ChangePasswordRequest;
|
|
import com.zioinfo.mes.auth.dto.OtpConfirmRequest;
|
|
import com.zioinfo.mes.auth.dto.OtpSetupResponse;
|
|
import com.zioinfo.mes.auth.dto.OtpVerifyRequest;
|
|
import com.zioinfo.mes.common.ApiResponse;
|
|
import com.zioinfo.mes.uiws.auth.OtpAuthService;
|
|
import com.zioinfo.mes.uiws.auth.TwoFactorService;
|
|
import com.zioinfo.mes.uiws.common.UiwsApiException;
|
|
import com.zioinfo.mes.uiws.common.UiwsErrorCode;
|
|
import jakarta.validation.Valid;
|
|
import lombok.RequiredArgsConstructor;
|
|
import org.springframework.web.bind.annotation.*;
|
|
|
|
import java.util.Map;
|
|
|
|
/**
|
|
* MES 인증 컨트롤러.
|
|
* - /login: 2FA off 면 { token, type, twofa:"false" }, 2FA on 이면 { twofa:"true", verifyToken, verifyMethod|step, ... }.
|
|
* - /verify: (UIWS 2FA 이식) verify-token + 이메일코드 → access/refresh 발급.
|
|
* - /verify-otp: (TOTP 이식) verify-token + 6자리 → access/refresh 발급(최초 로그인이면 등록 확정).
|
|
* 기존 클라이언트(2FA off)는 응답 형태 token 보존 → 회귀 0.
|
|
*/
|
|
@RestController
|
|
@RequestMapping("/api/mes/auth")
|
|
@RequiredArgsConstructor
|
|
public class AuthController {
|
|
|
|
private final AuthService authService;
|
|
private final TwoFactorService twoFactorService;
|
|
private final OtpAuthService otpAuthService;
|
|
private final JwtUtil jwtUtil;
|
|
|
|
@PostMapping("/login")
|
|
public ApiResponse<Map<String, String>> login(@RequestBody LoginRequest req) {
|
|
return ApiResponse.ok(authService.login(req.username(), req.password()));
|
|
}
|
|
|
|
/** UIWS 2FA(이메일코드) 이식: 2차 인증 코드 검증 → access/refresh 발급. */
|
|
@PostMapping("/verify")
|
|
public ApiResponse<Map<String, String>> verify(@RequestBody VerifyRequest req) {
|
|
return ApiResponse.ok(twoFactorService.verify(req.verifyToken(), req.code()));
|
|
}
|
|
|
|
/** TOTP 이식: 로그인 2단계 6자리 검증 → access/refresh 발급(최초 로그인이면 등록 확정). */
|
|
@PostMapping("/verify-otp")
|
|
public ApiResponse<Map<String, String>> verifyOtp(@Valid @RequestBody OtpVerifyRequest req) {
|
|
return ApiResponse.ok(otpAuthService.verifyOtp(req.verifyToken(), req.code()));
|
|
}
|
|
|
|
@GetMapping("/me")
|
|
public ApiResponse<Map<String, Object>> me(@RequestHeader("Authorization") String header) {
|
|
String token = header.replace("Bearer ", "");
|
|
return ApiResponse.ok(authService.me(token));
|
|
}
|
|
|
|
// ── 마이페이지: OTP 등록/재설정/해제 + 비밀번호 변경 (본인, access 토큰 필요) ──────────
|
|
|
|
/** 마이페이지 OTP 등록/재설정 시작 → { secret, otpAuthUri, qrImage }(이 응답에서만 시크릿/QR 노출). */
|
|
@PostMapping("/otp/setup")
|
|
public ApiResponse<OtpSetupResponse> otpSetup(@RequestHeader("Authorization") String header) {
|
|
return ApiResponse.ok(otpAuthService.setup(requireUser(header)));
|
|
}
|
|
|
|
/** 마이페이지 OTP 확인·활성화(앱 6자리 코드). */
|
|
@PostMapping("/otp/confirm")
|
|
public ApiResponse<Map<String, String>> otpConfirm(@RequestHeader("Authorization") String header,
|
|
@Valid @RequestBody OtpConfirmRequest req) {
|
|
otpAuthService.confirm(requireUser(header), req.code());
|
|
return ApiResponse.ok(Map.of("result", "ok"));
|
|
}
|
|
|
|
/** 마이페이지 OTP 해제. */
|
|
@PostMapping("/otp/disable")
|
|
public ApiResponse<Map<String, String>> otpDisable(@RequestHeader("Authorization") String header) {
|
|
otpAuthService.disable(requireUser(header));
|
|
return ApiResponse.ok(Map.of("result", "ok"));
|
|
}
|
|
|
|
/** 마이페이지 비밀번호 변경(현재 비번 검증 + BCrypt). 새 비번은 응답/로그 미포함. */
|
|
@PostMapping("/change-password")
|
|
public ApiResponse<Map<String, String>> changePassword(@RequestHeader("Authorization") String header,
|
|
@Valid @RequestBody ChangePasswordRequest req) {
|
|
authService.changePassword(requireUser(header), req);
|
|
return ApiResponse.ok(Map.of("result", "ok"));
|
|
}
|
|
|
|
/**
|
|
* Authorization 헤더에서 인증 사용자를 해석한다. verify-token(2fa 단계용)은 거부.
|
|
* (/api/mes/auth/** 는 permitAll 이라 필터 인증이 없으므로 여기서 access 토큰을 명시 검증.)
|
|
*/
|
|
private String requireUser(String header) {
|
|
String token = header == null ? "" : header.replace("Bearer ", "").trim();
|
|
if (token.isEmpty() || jwtUtil.isVerifyToken(token) || !jwtUtil.isValid(token)) {
|
|
throw new UiwsApiException(UiwsErrorCode.UNAUTHORIZED);
|
|
}
|
|
return jwtUtil.getUsername(token);
|
|
}
|
|
|
|
record LoginRequest(String username, String password) {}
|
|
|
|
record VerifyRequest(String verifyToken, String code) {}
|
|
}
|