diff --git a/powerjob-client/src/main/java/tech/powerjob/client/service/impl/AppAuthClusterRequestService.java b/powerjob-client/src/main/java/tech/powerjob/client/service/impl/AppAuthClusterRequestService.java index ddf8120d..804a2ad8 100644 --- a/powerjob-client/src/main/java/tech/powerjob/client/service/impl/AppAuthClusterRequestService.java +++ b/powerjob-client/src/main/java/tech/powerjob/client/service/impl/AppAuthClusterRequestService.java @@ -1,10 +1,19 @@ package tech.powerjob.client.service.impl; +import com.google.common.collect.Maps; +import lombok.SneakyThrows; +import org.apache.commons.lang3.StringUtils; import tech.powerjob.client.ClientConfig; import tech.powerjob.client.module.AppAuthRequest; import tech.powerjob.client.module.AppAuthResult; +import tech.powerjob.common.OpenAPIConstant; +import tech.powerjob.common.enums.ErrorCodes; +import tech.powerjob.common.exception.PowerJobException; +import tech.powerjob.common.serialize.JsonUtils; import tech.powerjob.common.utils.DigestUtils; +import java.util.Map; + /** * 封装鉴权相关逻辑 * @@ -19,15 +28,44 @@ abstract class AppAuthClusterRequestService extends ClusterRequestService { super(config); } - protected void refreshAuthInfo() { + + @Override + public String request(String path, Object body) { + // 若不存在 appAuthResult,则首先进行鉴权 + if (appAuthResult == null) { + refreshAppAuthResult(); + } + + Map authHeaders = buildAuthHeader(); + String clusterResponse = clusterHaRequest(path, body, authHeaders); + + // TODO + + return null; + } + + private Map buildAuthHeader() { + Map authHeader = Maps.newHashMap(); + authHeader.put(OpenAPIConstant.REQUEST_HEADER_APP_ID, String.valueOf(appAuthResult.getAppId())); + authHeader.put(OpenAPIConstant.REQUEST_HEADER_ACCESS_TOKEN, appAuthResult.getToken()); + return authHeader; + } + + @SneakyThrows + private void refreshAppAuthResult() { + AppAuthRequest appAuthRequest = buildAppAuthRequest(); + String authResponse = clusterHaRequest(OpenAPIConstant.AUTH_APP, appAuthRequest, null); + if (StringUtils.isEmpty(authResponse)) { + throw new PowerJobException(ErrorCodes.CLIENT_HTTP_REQUEST_FAILED, "EMPTY_RESPONSE"); + } + + this.appAuthResult = JsonUtils.parseObject(authResponse, AppAuthResult.class); + } + + protected AppAuthRequest buildAppAuthRequest() { AppAuthRequest appAuthRequest = new AppAuthRequest(); appAuthRequest.setAppName(config.getAppName()); appAuthRequest.setEncryptedPassword(DigestUtils.md5(config.getPassword())); - - try { - - } catch (Exception e) { - - } + return appAuthRequest; } } diff --git a/powerjob-client/src/main/java/tech/powerjob/client/service/impl/ClusterRequestService.java b/powerjob-client/src/main/java/tech/powerjob/client/service/impl/ClusterRequestService.java index 17520fb2..a75b5ad5 100644 --- a/powerjob-client/src/main/java/tech/powerjob/client/service/impl/ClusterRequestService.java +++ b/powerjob-client/src/main/java/tech/powerjob/client/service/impl/ClusterRequestService.java @@ -1,6 +1,5 @@ package tech.powerjob.client.service.impl; -import com.google.common.collect.Maps; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import tech.powerjob.client.ClientConfig; @@ -32,10 +31,6 @@ abstract class ClusterRequestService implements RequestService { * 当前地址(上次请求成功的地址) */ protected String currentAddress; - /** - * 鉴权相关 headers - */ - protected Map authHeaders = Maps.newHashMap(); /** * 地址格式 @@ -54,10 +49,24 @@ abstract class ClusterRequestService implements RequestService { this.config = config; } - protected abstract String sendHttpRequest(String url, String body) throws IOException; + /** + * 具体某一次 HTTP 请求的实现 + * @param url 完整请求地址 + * @param body 请求体 + * @param headers 请求头 + * @return 响应 + * @throws IOException 异常 + */ + protected abstract String sendHttpRequest(String url, String body, Map headers) throws IOException; - @Override - public String request(String path, Object obj) { + /** + * 封装集群请求能力 + * @param path 请求 PATH + * @param obj 请求体 + * @param headers 请求头 + * @return 响应 + */ + protected String clusterHaRequest(String path, Object obj, Map headers) { String body = obj instanceof String ? (String) obj : JsonUtils.toJSONStringUnsafe(obj); @@ -65,7 +74,7 @@ abstract class ClusterRequestService implements RequestService { // 先尝试默认地址 String url = getUrl(path, currentAddress); try { - String res = sendHttpRequest(url, body); + String res = sendHttpRequest(url, body, headers); if (StringUtils.isNotEmpty(res)) { return res; } @@ -80,7 +89,7 @@ abstract class ClusterRequestService implements RequestService { } url = getUrl(path, addr); try { - String res = sendHttpRequest(url, body); + String res = sendHttpRequest(url, body, headers); if (StringUtils.isNotEmpty(res)) { log.warn("[ClusterRequestService] server change: from({}) -> to({}).", currentAddress, addr); currentAddress = addr; diff --git a/powerjob-client/src/main/java/tech/powerjob/client/service/impl/ClusterRequestServiceOkHttp3Impl.java b/powerjob-client/src/main/java/tech/powerjob/client/service/impl/ClusterRequestServiceOkHttp3Impl.java index 8778ce64..f85c81b4 100644 --- a/powerjob-client/src/main/java/tech/powerjob/client/service/impl/ClusterRequestServiceOkHttp3Impl.java +++ b/powerjob-client/src/main/java/tech/powerjob/client/service/impl/ClusterRequestServiceOkHttp3Impl.java @@ -40,13 +40,22 @@ public class ClusterRequestServiceOkHttp3Impl extends ClusterRequestService { } @Override - protected String sendHttpRequest(String url, String payload) throws IOException { + public String request(String path, Object body) { + // TODO + return null; + } + + @Override + protected String sendHttpRequest(String url, String payload, Map h) throws IOException { // 公共 header Map headers = Maps.newHashMap(); if (config.getDefaultHeaders() != null) { headers.putAll(config.getDefaultHeaders()); } + if (h != null) { + headers.putAll(h); + } MediaType jsonType = MediaType.parse(OmsConstant.JSON_MEDIA_TYPE); RequestBody requestBody = RequestBody.create(jsonType, payload); diff --git a/powerjob-common/src/main/java/tech/powerjob/common/OpenAPIConstant.java b/powerjob-common/src/main/java/tech/powerjob/common/OpenAPIConstant.java index 6be3f17c..2d7d8f55 100644 --- a/powerjob-common/src/main/java/tech/powerjob/common/OpenAPIConstant.java +++ b/powerjob-common/src/main/java/tech/powerjob/common/OpenAPIConstant.java @@ -61,7 +61,9 @@ public class OpenAPIConstant { /* ************* 鉴权 ************* */ - public static final String HEADER_ACCESS_TOKEN = "X-POWERJOB-ACCESS-TOKEN"; + public static final String REQUEST_HEADER_ACCESS_TOKEN = "X-POWERJOB-ACCESS-TOKEN"; - public static final String HEADER_APP_ID = "X-POWERJOB-APP-ID"; + public static final String REQUEST_HEADER_APP_ID = "X-POWERJOB-APP-ID"; + + public static final String RESPONSE_HEADER_AUTH_STATUS = "X-POWERJOB-AUTH-PASSED"; } diff --git a/powerjob-common/src/main/java/tech/powerjob/common/enums/ErrorCodes.java b/powerjob-common/src/main/java/tech/powerjob/common/enums/ErrorCodes.java index 81a65792..efe05fee 100644 --- a/powerjob-common/src/main/java/tech/powerjob/common/enums/ErrorCodes.java +++ b/powerjob-common/src/main/java/tech/powerjob/common/enums/ErrorCodes.java @@ -46,6 +46,11 @@ public enum ErrorCodes { OPEN_API_PASSWORD_ERROR("-1001", "OPEN_API_PASSWORD_ERROR"), OPEN_API_AUTH_FAILED("-1002", "OPEN_API_AUTH_FAILED"), + /** + * PowerJobClient 错误码号段 + */ + CLIENT_HTTP_REQUEST_FAILED("-2001", "CLIENT_HTTP_REQUEST_FAILED"), + ; private final String code; diff --git a/powerjob-common/src/main/java/tech/powerjob/common/serialize/JsonUtils.java b/powerjob-common/src/main/java/tech/powerjob/common/serialize/JsonUtils.java index 9a4d52ac..dbdab14d 100644 --- a/powerjob-common/src/main/java/tech/powerjob/common/serialize/JsonUtils.java +++ b/powerjob-common/src/main/java/tech/powerjob/common/serialize/JsonUtils.java @@ -2,7 +2,6 @@ package tech.powerjob.common.serialize; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.MapperFeature; @@ -86,7 +85,7 @@ public class JsonUtils { return null; } - public static T parseObject(String json, Class clz) throws JsonProcessingException { + public static T parseObject(String json, Class clz) throws Exception { return JSON_MAPPER.readValue(json, clz); } diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/openapi/OpenApiInterceptor.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/openapi/OpenApiInterceptor.java index 3622f3c2..ecd632eb 100644 --- a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/openapi/OpenApiInterceptor.java +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/openapi/OpenApiInterceptor.java @@ -1,11 +1,14 @@ package tech.powerjob.server.openapi; +import com.google.common.collect.Sets; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.lang.NonNull; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; +import tech.powerjob.common.OmsConstant; +import tech.powerjob.common.OpenAPIConstant; import tech.powerjob.common.exception.PowerJobException; import tech.powerjob.common.response.PowerResultDTO; import tech.powerjob.common.serialize.JsonUtils; @@ -15,6 +18,7 @@ import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.PrintWriter; +import java.util.Set; /** * OpenAPI 拦截器 @@ -36,6 +40,8 @@ public class OpenApiInterceptor implements HandlerInterceptor { @Value("${oms.auth.openapi.enable:false}") private boolean enableOpenApiAuth; + private static final Set IGNORE_OPEN_API_PATH = Sets.newHashSet(OpenAPIConstant.ASSERT, OpenAPIConstant.AUTH_APP); + @Override public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler) throws Exception { @@ -43,15 +49,27 @@ public class OpenApiInterceptor implements HandlerInterceptor { return true; } + // 鉴权类请求跳过拦截 + String requestURI = request.getRequestURI(); + for (String endPath : IGNORE_OPEN_API_PATH) { + if (requestURI.endsWith(endPath)) { + return true; + } + } + try { openApiSecurityService.authAppByToken(request); + response.addHeader(OpenAPIConstant.RESPONSE_HEADER_AUTH_STATUS, Boolean.TRUE.toString()); } catch (PowerJobException pje) { - PowerResultDTO ret = PowerResultDTO.f(pje); - writeResponse(JsonUtils.toJSONString(ret), response); + response.addHeader(OpenAPIConstant.RESPONSE_HEADER_AUTH_STATUS, Boolean.FALSE.toString()); + writeResponse(PowerResultDTO.f(pje), response); return false; } catch (Exception e) { - PowerResultDTO ret = PowerResultDTO.f(e); - writeResponse(JsonUtils.toJSONString(ret), response); + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + writeResponse(PowerResultDTO.f(e), response); + + log.error("[OpenApiInterceptor] unknown exception when auth app by token", e); + return false; } @@ -59,16 +77,14 @@ public class OpenApiInterceptor implements HandlerInterceptor { } @SneakyThrows - private void writeResponse(String content, HttpServletResponse response) { - // 设置响应状态码,通常是 400, 401, 403 等错误码 - response.setStatus(HttpServletResponse.SC_FORBIDDEN); + private void writeResponse( PowerResultDTO powerResult, HttpServletResponse response) { // 设置响应的 Content-Type - response.setContentType("application/json;charset=UTF-8"); + response.setContentType(OmsConstant.JSON_MEDIA_TYPE); // 将 JSON 写入响应 PrintWriter writer = response.getWriter(); - writer.write(content); + writer.write(JsonUtils.toJSONString(powerResult)); writer.flush(); } diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/openapi/security/OpenApiSecurityServiceImpl.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/openapi/security/OpenApiSecurityServiceImpl.java index 26264edc..2533a583 100644 --- a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/openapi/security/OpenApiSecurityServiceImpl.java +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/openapi/security/OpenApiSecurityServiceImpl.java @@ -44,8 +44,8 @@ public class OpenApiSecurityServiceImpl implements OpenApiSecurityService { @Override public void authAppByToken(HttpServletRequest httpServletRequest) { - String token = HttpServletUtils.fetchFromHeader(OpenAPIConstant.HEADER_ACCESS_TOKEN, httpServletRequest); - String appIdFromHeader = HttpServletUtils.fetchFromHeader(OpenAPIConstant.HEADER_APP_ID, httpServletRequest); + String token = HttpServletUtils.fetchFromHeader(OpenAPIConstant.REQUEST_HEADER_ACCESS_TOKEN, httpServletRequest); + String appIdFromHeader = HttpServletUtils.fetchFromHeader(OpenAPIConstant.REQUEST_HEADER_APP_ID, httpServletRequest); if (StringUtils.isEmpty(appIdFromHeader)) { throw new PowerJobException(ErrorCodes.INVALID_REQUEST, "lack_of_appId_in_header");