diff --git a/src/main/java/kr/re/etri/autoflow/controllers/ExternalAuthController.java b/src/main/java/kr/re/etri/autoflow/controllers/ExternalAuthController.java new file mode 100644 index 0000000..bd6a533 --- /dev/null +++ b/src/main/java/kr/re/etri/autoflow/controllers/ExternalAuthController.java @@ -0,0 +1,58 @@ +package kr.re.etri.autoflow.controllers; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import kr.re.etri.autoflow.service.ExternalAuthService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/api/external-auth") +@Tag(name = "ExternalAuthController", description = "외부 백엔드 로그인 및 Bearer 토큰 조회 API") +@RequiredArgsConstructor +public class ExternalAuthController { + + private final ExternalAuthService externalAuthService; + + @Operation(summary = "외부 로그인 후 Bearer 토큰 조회", description = "외부 Spring 백엔드에 로그인 요청 후 Bearer 토큰을 반환합니다.") + @PostMapping("/signin") + public ResponseEntity signin( + @RequestBody SigninRequest request + ) { + try { + String token = externalAuthService.getBearerToken(request.id(), request.password()); + return ResponseEntity.ok(ApiResponse.success(token)); + } catch (Exception e) { + return ResponseEntity.ok(ApiResponse.failure(e.getMessage())); + } + } + + // DTO: 요청 + public static record SigninRequest(String id, String password) { } + + // DTO: 응답 + public static class ApiResponse { + private boolean success; + private Object data; + private String errorMessage; + + public ApiResponse(boolean success, Object data, String errorMessage) { + this.success = success; + this.data = data; + this.errorMessage = errorMessage; + } + + public static ApiResponse success(Object data) { + return new ApiResponse(true, data, null); + } + + public static ApiResponse failure(String errorMessage) { + return new ApiResponse(false, null, errorMessage); + } + + public boolean isSuccess() { return success; } + public Object getData() { return data; } + public String getErrorMessage() { return errorMessage; } + } +} diff --git a/src/main/java/kr/re/etri/autoflow/service/ExternalAuthService.java b/src/main/java/kr/re/etri/autoflow/service/ExternalAuthService.java new file mode 100644 index 0000000..d1c771a --- /dev/null +++ b/src/main/java/kr/re/etri/autoflow/service/ExternalAuthService.java @@ -0,0 +1,65 @@ +package kr.re.etri.autoflow.service; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.*; +import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import javax.net.ssl.*; +import java.security.cert.X509Certificate; +import java.util.Map; + + +@Service +public class ExternalAuthService { + + @Value("${external.auth.signin-url}") + private String signinUrl; + + private final RestTemplate restTemplate; + + public ExternalAuthService() throws Exception { + // SSLContext 생성 (모든 인증서 허용) + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, new TrustManager[]{new X509TrustManager() { + public void checkClientTrusted(X509Certificate[] chain, String authType) {} + public void checkServerTrusted(X509Certificate[] chain, String authType) {} + public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } + }}, new java.security.SecureRandom()); + + HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); + HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true); + + this.restTemplate = new RestTemplate(new SimpleClientHttpRequestFactory()); + } + + public String getBearerToken(String id, String password) { + + Map body = Map.of( + "id", id, + "password", password + ); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + + HttpEntity> request = new HttpEntity<>(body, headers); + + ResponseEntity response = restTemplate.exchange( + signinUrl, + HttpMethod.POST, + request, + Map.class + ); + + if (response.getStatusCode() == HttpStatus.OK) { + Map respBody = response.getBody(); + if (respBody != null && respBody.get("data") instanceof Map dataMap) { + return (String) dataMap.get("token"); + } + } + + throw new RuntimeException("Failed to get Bearer token"); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 84c34e6..11c364d 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -5,6 +5,7 @@ spring.profiles.active=local spring.datasource.url=jdbc:mariadb://192.168.10.143:3306/autoflow +spring.datasource.driver-class-name=org.mariadb.jdbc.Driver spring.datasource.username=cuuva spring.datasource.password=cuuva @@ -68,3 +69,7 @@ server.servlet.encoding.force=true spring.servlet.multipart.enabled=true +#OTA?? +external.auth.signin-url=https://cuuva.com:24443/api/datamanager/user/signin + +