Skip to content

Commit

Permalink
perf: esb api normalization TencentBlueKing#79
Browse files Browse the repository at this point in the history
  • Loading branch information
tyleryuwang committed Jul 12, 2021
1 parent 5891934 commit b314228
Show file tree
Hide file tree
Showing 102 changed files with 806 additions and 270 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,31 @@

package com.tencent.bk.job.common.web.filter;

import com.tencent.bk.job.common.web.model.RepeatableReadHttpServletRequest;
import com.tencent.bk.job.common.web.model.RepeatableReadHttpServletResponse;
import com.tencent.bk.job.common.web.model.RepeatableReadWriteHttpServletRequest;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.*;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Slf4j
public class RepeatableReadServletRequestResponseFilter implements Filter {
public class RepeatableReadWriteServletRequestResponseFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
public void init(FilterConfig filterConfig) {

}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException {
ServletRequest requestWrapper = new RepeatableReadHttpServletRequest((HttpServletRequest) request);
ServletRequest requestWrapper = new RepeatableReadWriteHttpServletRequest((HttpServletRequest) request);
ServletResponse responseWrapper = new RepeatableReadHttpServletResponse((HttpServletResponse) response);
chain.doFilter(requestWrapper, responseWrapper);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import com.tencent.bk.job.common.util.json.JsonUtils;
import com.tencent.bk.job.common.web.model.RepeatableReadHttpServletRequest;
import com.tencent.bk.job.common.web.model.RepeatableReadHttpServletResponse;
import com.tencent.bk.job.common.web.model.RepeatableReadWriteHttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpMethod;
Expand All @@ -45,10 +45,10 @@ public class EsbApiLogInterceptor extends HandlerInterceptorAdapter {

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
if (!(request instanceof RepeatableReadHttpServletRequest)) {
if (!(request instanceof RepeatableReadWriteHttpServletRequest)) {
return true;
}
RepeatableReadHttpServletRequest wrapperRequest = (RepeatableReadHttpServletRequest) request;
RepeatableReadWriteHttpServletRequest wrapperRequest = (RepeatableReadWriteHttpServletRequest) request;
String desensitizedBody = "";
String desensitizedQueryParams = "";
String username = "";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Tencent is pleased to support the open source community by making BK-JOB蓝鲸智云作业平台 available.
*
* Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
*
* BK-JOB蓝鲸智云作业平台 is licensed under the MIT License.
*
* License for BK-JOB蓝鲸智云作业平台:
* --------------------------------------------------------------------
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of
* the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/

package com.tencent.bk.job.common.web.interceptor;

import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import com.tencent.bk.job.common.constant.JobCommonHeaders;
import com.tencent.bk.job.common.util.json.JsonUtils;
import com.tencent.bk.job.common.web.model.RepeatableReadWriteHttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Slf4j
@Component
public class EsbReqRewriteInterceptor extends HandlerInterceptorAdapter {

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
if (!(request instanceof RepeatableReadWriteHttpServletRequest)) {
return true;
}
RepeatableReadWriteHttpServletRequest wrapperRequest = (RepeatableReadWriteHttpServletRequest) request;

String appCode = request.getHeader(JobCommonHeaders.APP_CODE);
String username = request.getHeader(JobCommonHeaders.USERNAME);

try {
if (request.getMethod().equals(HttpMethod.POST.name())
|| request.getMethod().equals(HttpMethod.PUT.name())) {
if (StringUtils.isNotBlank(wrapperRequest.getBody())) {
ObjectNode jsonBody = (ObjectNode) JsonUtils.toJsonNode(wrapperRequest.getBody());
if (jsonBody == null) {
return true;
}
// reset username and appCode
if (StringUtils.isNotBlank(username)) {
String usernameInBody = jsonBody.get("bk_username").asText();
if (StringUtils.isNotEmpty(usernameInBody) && !usernameInBody.equals(username)) {
log.error("Invalid username, usernameInBody: {}, username: {}", usernameInBody, username);
}
jsonBody.set("bk_username", new TextNode(username));
} else {
log.error("Header {} is missing", JobCommonHeaders.USERNAME);
}

if (StringUtils.isNotBlank(appCode)) {
String appCodeInBody = jsonBody.get("bk_app_code").asText();
if (StringUtils.isNotEmpty(appCodeInBody) && !appCodeInBody.equals(appCode)) {
log.error("Invalid appCode, appCodeInBody: {}, appCode: {}", appCodeInBody, appCode);
}
jsonBody.set("bk_app_code", new TextNode(appCode));
} else {
log.error("Header {} is missing", JobCommonHeaders.APP_CODE);
}

// hidden sensitive data
jsonBody.set("bk_app_secret", TextNode.valueOf("***"));
wrapperRequest.setBody(jsonBody.toString());
}
}
} catch (Throwable e) {
log.warn("Rewrite EsbReq error", e);
return true;
}
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,21 @@
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;

/**
* 由于HttpServletRequest的InputStream只允许读取一次,为了能够重复读取body,需要用装饰模式来包装
* 由于HttpServletRequest的InputStream只允许读取一次,为了能够重复读写body,需要用装饰模式来包装
*/
@Slf4j
public class RepeatableReadHttpServletRequest extends HttpServletRequestWrapper {
private final String body;
public class RepeatableReadWriteHttpServletRequest extends HttpServletRequestWrapper {
private String body;

public RepeatableReadHttpServletRequest(HttpServletRequest request) {
public RepeatableReadWriteHttpServletRequest(HttpServletRequest request) {
super(request);
StringBuilder stringBuilder = new StringBuilder();
BufferedReader br = null;
Expand Down Expand Up @@ -103,4 +107,8 @@ public BufferedReader getReader() {
public String getBody() {
return this.body;
}

public void setBody(String newBody) {
this.body = newBody;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,10 @@
* IN THE SOFTWARE.
*/

package com.tencent.bk.job.common.esb.consts;

/**
* 常量定义
*/
public final class BkConsts {

public static final String X_CSRF_KEY = "X-CSRFToken";
public static final String CSRF_KEY = "csrftoken";
public static final String C_BK_TOKEN = "bk_token";
public static final String C_BK_UID = "bk_uid";
public static final String C_BK_TICKET = "bk_ticket";
public static final String SYS_LANGUAGE = "lang";
public static final String USER_SESSION = "user";

public static final String STATIC_VERSION = "STATIC_VERSION"; // 静态资源URL
public static final String APP_ID = "APP_ID";
public static final String SITE_URL = "SITE_URL"; //APP URL
package com.tencent.bk.job.common.constant;

public interface JobCommonHeaders {

public static final String TZ_ASIA_SHANGHAI = "Asia/Shanghai";
String APP_CODE = "X-AppCode";
String USERNAME = "X-Username";
}
1 change: 1 addition & 0 deletions src/backend/commons/esb-sdk/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ dependencies {
implementation 'io.springfox:springfox-swagger2'
compile 'org.apache.commons:commons-lang3'
implementation "org.springframework:spring-jdbc"
implementation 'org.springframework:spring-web'
implementation "net.sf.dozer:dozer"
implementation 'org.apache.commons:commons-collections4'
implementation 'net.sourceforge.jchardet:jchardet'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

package com.tencent.bk.job.common.esb.metrics;

import com.tencent.bk.job.common.esb.model.EsbReq;
import com.tencent.bk.job.common.constant.JobCommonHeaders;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Tags;
Expand All @@ -35,7 +35,11 @@
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;


Expand All @@ -61,29 +65,21 @@ public static Tag exception(Throwable exception) {

@Around("execution (@com.tencent.bk.job.common.esb.metrics.EsbApiTimed * *.*(..))")
public Object timedMethod(ProceedingJoinPoint pjp) throws Throwable {
Object[] args = pjp.getArgs();
if (args == null || args.length == 0) {
return pjp.proceed();
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
HttpServletRequest request = null;
if (requestAttributes != null) {
request = ((ServletRequestAttributes)requestAttributes).getRequest();
}

String appCode = "";
try {
for (Object arg : args) {
if (arg instanceof EsbReq) {
EsbReq esbReq = (EsbReq) arg;
appCode = esbReq.getAppCode();
break;
}
}
} catch (Throwable e) {
log.error("Process EsbReq fail!", e);
if (request == null) {
return pjp.proceed();
}

String appCode = request.getHeader(JobCommonHeaders.APP_CODE);
Tags tags = Tags.of("app_code", StringUtils.isNotBlank(appCode) ? appCode : "None");

Method method = ((MethodSignature) pjp.getSignature()).getMethod();
EsbApiTimed timed = method.getAnnotation(EsbApiTimed.class);
final String metricName = timed.value();
Tags tags = Tags.of("app_code", StringUtils.isNotBlank(appCode) ? appCode : "None");
return processWithTimer(pjp, timed, metricName, tags);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

package com.tencent.bk.job.analysis.config;

import com.tencent.bk.job.common.web.filter.RepeatableReadServletRequestResponseFilter;
import com.tencent.bk.job.common.web.filter.RepeatableReadWriteServletRequestResponseFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Expand All @@ -33,7 +33,7 @@
public class FilterConfig {
@Bean
public FilterRegistrationBean repeatableRSRRFilterRegister() {
FilterRegistrationBean<RepeatableReadServletRequestResponseFilter> registration =
FilterRegistrationBean<RepeatableReadWriteServletRequestResponseFilter> registration =
new FilterRegistrationBean<>();
registration.setFilter(repeatableRRRFilter());
registration.addUrlPatterns("/esb/api/*");
Expand All @@ -43,7 +43,7 @@ public FilterRegistrationBean repeatableRSRRFilterRegister() {
}

@Bean(name = "repeatableReadRequestResponseFilter")
public RepeatableReadServletRequestResponseFilter repeatableRRRFilter() {
return new RepeatableReadServletRequestResponseFilter();
public RepeatableReadWriteServletRequestResponseFilter repeatableRRRFilter() {
return new RepeatableReadWriteServletRequestResponseFilter();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
package com.tencent.bk.job.analysis.config;

import com.tencent.bk.job.analysis.interceptor.UriPermissionInterceptor;
import com.tencent.bk.job.common.web.interceptor.EsbApiLogInterceptor;
import com.tencent.bk.job.common.web.interceptor.JobCommonInterceptor;
import com.tencent.bk.job.common.web.interceptor.ServiceSecurityInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -37,17 +36,14 @@
public class InterceptorConfiguration implements WebMvcConfigurer {

private final JobCommonInterceptor jobCommonInterceptor;
private final EsbApiLogInterceptor esbApiLogInterceptor;
private final ServiceSecurityInterceptor serviceSecurityInterceptor;
private final UriPermissionInterceptor uriPermissionInterceptor;

@Autowired
public InterceptorConfiguration(JobCommonInterceptor jobCommonInterceptor,
EsbApiLogInterceptor esbApiLogInterceptor,
ServiceSecurityInterceptor serviceSecurityInterceptor,
UriPermissionInterceptor uriPermissionInterceptor) {
this.jobCommonInterceptor = jobCommonInterceptor;
this.esbApiLogInterceptor = esbApiLogInterceptor;
this.serviceSecurityInterceptor = serviceSecurityInterceptor;
this.uriPermissionInterceptor = uriPermissionInterceptor;
}
Expand All @@ -59,6 +55,5 @@ public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(jobCommonInterceptor).addPathPatterns("/**").order(1);
registry.addInterceptor(uriPermissionInterceptor)
.addPathPatterns(uriPermissionInterceptor.getControlUriPatterns()).order(2);
registry.addInterceptor(esbApiLogInterceptor).addPathPatterns("/esb/api/**").order(10);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,11 @@
public interface EsbCronJobResource {

@PostMapping("/get_cron_list")
EsbResp<List<EsbCronInfoResponse>> getCronList(
@RequestHeader(value = COMMON_LANG_HEADER, required = false) String lang,
@RequestBody EsbGetCronListRequest request);
EsbResp<List<EsbCronInfoResponse>> getCronList(@RequestBody EsbGetCronListRequest request);

@PostMapping(value = "/update_cron_status")
EsbResp<EsbCronInfoResponse> updateCronStatus(
@RequestHeader(value = COMMON_LANG_HEADER, required = false) String lang,
@RequestBody EsbUpdateCronStatusRequest request);
EsbResp<EsbCronInfoResponse> updateCronStatus(@RequestBody EsbUpdateCronStatusRequest request);

@PostMapping(value = "/save_cron")
EsbResp<EsbCronInfoResponse> saveCron(@RequestHeader(value = COMMON_LANG_HEADER, required = false) String lang,
@RequestBody EsbSaveCronRequest request);
EsbResp<EsbCronInfoResponse> saveCron(@RequestBody EsbSaveCronRequest request);
}
Loading

0 comments on commit b314228

Please sign in to comment.