From c118c88dceb372f6c7cf4f491a099939259346d2 Mon Sep 17 00:00:00 2001 From: curry772 Date: Mon, 20 Jul 2026 11:12:13 +0900 Subject: [PATCH] =?UTF-8?q?=EC=96=B4=EB=8C=91=ED=84=B0=EB=B3=84=20apikey?= =?UTF-8?q?=20=ED=97=A4=EB=8D=94=EB=AA=85=20=EB=8F=99=EC=A0=81=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../http/dynamic/HttpAdapterServiceKey.java | 4 + .../http/dynamic/filter/ApiAuthFilter.java | 77 ++++++++++++------- 2 files changed, 52 insertions(+), 29 deletions(-) diff --git a/src/main/java/com/eactive/eai/adapter/http/dynamic/HttpAdapterServiceKey.java b/src/main/java/com/eactive/eai/adapter/http/dynamic/HttpAdapterServiceKey.java index b662e26..b3dd3cf 100644 --- a/src/main/java/com/eactive/eai/adapter/http/dynamic/HttpAdapterServiceKey.java +++ b/src/main/java/com/eactive/eai/adapter/http/dynamic/HttpAdapterServiceKey.java @@ -85,4 +85,8 @@ public interface HttpAdapterServiceKey { //응답 처리 용 표준 전문 오브젝트 static final String STANDARD_MESSAGE_OBJECT = "STANDARD_MESSAGE_OBJECT"; + + // 어댑터별 인증 키 헤더 이름 + static final String ADAPTER_TOKEN_HEADER_NAME = "ADAPTER_TOKEN_HEADER_NAME"; + static final String ADAPTER_APIKEY_HEADER_NAME = "ADAPTER_APIKEY_HEADER_NAME"; } diff --git a/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/ApiAuthFilter.java b/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/ApiAuthFilter.java index 1375027..d93863c 100644 --- a/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/ApiAuthFilter.java +++ b/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/ApiAuthFilter.java @@ -1,5 +1,26 @@ package com.eactive.eai.adapter.http.dynamic.filter; +import java.io.IOException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.X509EncodedKeySpec; +import java.text.ParseException; +import java.util.Base64; +import java.util.Date; +import java.util.HashSet; +import java.util.Properties; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; + +import com.eactive.eai.adapter.http.dynamic.HttpAdapterServiceKey; import com.eactive.eai.adapter.http.dynamic.HttpAdapterServiceSupport; import com.eactive.eai.authserver.service.BearerTokenInfo; //import com.eactive.eai.authserver.vo.BearerTokenInfo; @@ -13,7 +34,6 @@ import com.eactive.eai.common.property.PropManager; import com.eactive.eai.common.session.SessionManager; import com.eactive.eai.common.stdmessage.STDMessageManager; import com.eactive.eai.common.util.Logger; -import com.eactive.eai.common.util.StringUtil; import com.eactive.eai.inbound.action.ActionFactory; import com.eactive.eai.inbound.action.RequestAction; import com.eactive.eai.inbound.processor.Processor; @@ -25,27 +45,6 @@ import com.nimbusds.jose.crypto.RSASSAVerifier; import com.nimbusds.jose.util.IOUtils; import com.nimbusds.jwt.SignedJWT; -import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.lang3.StringUtils; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.interfaces.RSAPublicKey; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.X509EncodedKeySpec; -import java.text.ParseException; -import java.util.Base64; -import java.util.Date; -import java.util.HashSet; -import java.util.Map; -import java.util.Properties; -import java.util.concurrent.ConcurrentHashMap; - public class ApiAuthFilter implements HttpAdapterFilter { static Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER); @@ -124,7 +123,7 @@ public class ApiAuthFilter implements HttpAdapterFilter { switch (eaiMessage.getAuthType()){ case "oauth": try { - String token = extractBearerToken(request); + String token = extractBearerToken(request, prop); SignedJWT signedJWT = SignedJWT.parse(token); if (signedJWT.getJWTClaimsSet().getExpirationTime() == null) { @@ -182,8 +181,23 @@ public class ApiAuthFilter implements HttpAdapterFilter { } break; case "api_key": - String apiKeyName = PropManager.getInstance().getProperty("ApiConfig", "api.key.name", "x-api-key"); - String apiKey = request.getHeader(apiKeyName); + // 기관별로 API Key 헤더명이 다를 수 있어, 어댑터별 설정(ADAPTER_TOKEN_HEADER_NAME)을 우선 사용하고 + // 없으면 ApiConfig 전역 설정(api.key.name)을 사용. 콤마로 다중 헤더명 지정 시 순서대로 값이 있는 헤더를 사용 + String apiKeyNameConf = prop.getProperty(HttpAdapterServiceKey.ADAPTER_APIKEY_HEADER_NAME); + if (StringUtils.isBlank(apiKeyNameConf)) { + apiKeyNameConf = PropManager.getInstance().getProperty("ApiConfig", "api.key.name", "x-api-key"); + } + String[] apiKeyNames = org.springframework.util.StringUtils.tokenizeToStringArray(apiKeyNameConf, ","); + String apiKeyName = null; + String apiKey = null; + for (String name : apiKeyNames) { + String value = request.getHeader(name); + if (StringUtils.isNotBlank(value)) { + apiKeyName = name; + apiKey = value.trim(); + break; + } + } if(apiKey == null){ // QueryString으로 전달된 access_token 파라미터 확인 String apiKeyParamName = PropManager.getInstance().getProperty("ApiConfig", "api.key.param.name", "x-api-key"); @@ -191,14 +205,14 @@ public class ApiAuthFilter implements HttpAdapterFilter { if (StringUtils.isNotBlank(queryApiKey)) { apiKey = queryApiKey.trim(); } else { - throw new JwtAuthException(ERROR_AUTHENTICATION_FAIL, "Invalid or missing API key \""+apiKeyName+"\" in Http Header"); + throw new JwtAuthException(ERROR_AUTHENTICATION_FAIL, "Invalid or missing API key \""+apiKeyNameConf+"\" in Http Header"); } } prop.setProperty(HttpAdapterServiceSupport.PROPERTIES_NAME_CLIENT_ID, apiKey); isPassScope = true; break; case "ca": - String token = extractBearerToken(request); + String token = extractBearerToken(request, prop); BearerTokenInfo bearerTokenInfo = SessionManager.getInstance().getCAToken(token); if ( bearerTokenInfo != null ) { if( bearerTokenInfo.isExpired() ) { @@ -319,8 +333,13 @@ public class ApiAuthFilter implements HttpAdapterFilter { return false; } - public static String extractBearerToken(HttpServletRequest request) throws JwtAuthException { - String tokenHeaderName = PropManager.getInstance().getProperty("ApiConfig", "token.header.name", "Authorization"); + public static String extractBearerToken(HttpServletRequest request, Properties prop) throws JwtAuthException { + // 기관별로 토큰 헤더명이 다를 수 있어, 어댑터별 설정(ADAPTER_APPKEY_HEADER_NAME)을 우선 사용하고 + // 없으면 ApiConfig 전역 설정(token.header.name)을 사용 + String tokenHeaderName = prop != null ? prop.getProperty(HttpAdapterServiceKey.ADAPTER_TOKEN_HEADER_NAME) : null; + if (StringUtils.isBlank(tokenHeaderName)) { + tokenHeaderName = PropManager.getInstance().getProperty("ApiConfig", "token.header.name", "Authorization"); + } String authorization = request.getHeader(tokenHeaderName); if (StringUtils.isBlank(authorization)) { // QueryString으로 전달된 access_token 파라미터 확인