mirror of
https://github.com/PowerJob/PowerJob.git
synced 2025-07-17 00:00:04 +08:00
feat: OpenApiInterceptor
This commit is contained in:
parent
bee4795027
commit
53be566173
@ -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<String, String> authHeaders = buildAuthHeader();
|
||||
String clusterResponse = clusterHaRequest(path, body, authHeaders);
|
||||
|
||||
// TODO
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Map<String, String> buildAuthHeader() {
|
||||
Map<String, String> 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;
|
||||
}
|
||||
}
|
||||
|
@ -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<String, String> 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<String, String> 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<String, String> 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;
|
||||
|
@ -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<String, String> h) throws IOException {
|
||||
|
||||
// 公共 header
|
||||
Map<String, String> 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);
|
||||
|
@ -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";
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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> T parseObject(String json, Class<T> clz) throws JsonProcessingException {
|
||||
public static <T> T parseObject(String json, Class<T> clz) throws Exception {
|
||||
return JSON_MAPPER.readValue(json, clz);
|
||||
}
|
||||
|
||||
|
@ -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<String> 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<Object> 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<Object> 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<Object> 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();
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
|
Loading…
x
Reference in New Issue
Block a user