修改漏洞及添加网关拦截
This commit is contained in:
parent
43547fa0c9
commit
7470b59060
|
|
@ -57,7 +57,11 @@
|
||||||
<groupId>com.bonus</groupId>
|
<groupId>com.bonus</groupId>
|
||||||
<artifactId>common-security</artifactId>
|
<artifactId>common-security</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- SpringBoot Actuator -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.cloud</groupId>
|
<groupId>org.springframework.cloud</groupId>
|
||||||
<artifactId>spring-cloud-loadbalancer</artifactId>
|
<artifactId>spring-cloud-loadbalancer</artifactId>
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ public class TokenConstants
|
||||||
*/
|
*/
|
||||||
public static final String AUTHENTICATION = "Authorization";
|
public static final String AUTHENTICATION = "Authorization";
|
||||||
|
|
||||||
|
public static final String TOKEN_HEAD = "token";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 令牌前缀
|
* 令牌前缀
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -26,9 +26,13 @@ import com.bonus.common.core.web.domain.AjaxResult;
|
||||||
public class GlobalExceptionHandler
|
public class GlobalExceptionHandler
|
||||||
{
|
{
|
||||||
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
|
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
|
||||||
|
public final static String BODY_ERROR="Required request body is missing:";
|
||||||
|
|
||||||
|
public final static String DATA_ERROR="Data truncation: Data too long for";
|
||||||
|
|
||||||
|
public final static String NumberFormatException="java.lang.NumberFormatException";
|
||||||
/**
|
/**
|
||||||
* 权限码异常
|
* 权限码异常r
|
||||||
*/
|
*/
|
||||||
@ExceptionHandler(NotPermissionException.class)
|
@ExceptionHandler(NotPermissionException.class)
|
||||||
public AjaxResult handleNotPermissionException(NotPermissionException e, HttpServletRequest request)
|
public AjaxResult handleNotPermissionException(NotPermissionException e, HttpServletRequest request)
|
||||||
|
|
@ -58,7 +62,7 @@ public class GlobalExceptionHandler
|
||||||
{
|
{
|
||||||
String requestURI = request.getRequestURI();
|
String requestURI = request.getRequestURI();
|
||||||
log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod());
|
log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod());
|
||||||
return AjaxResult.error(e.getMessage());
|
return AjaxResult.error(HttpStatus.FORBIDDEN, "请求方式不支持");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -79,6 +83,15 @@ public class GlobalExceptionHandler
|
||||||
public AjaxResult handleRuntimeException(RuntimeException e, HttpServletRequest request)
|
public AjaxResult handleRuntimeException(RuntimeException e, HttpServletRequest request)
|
||||||
{
|
{
|
||||||
String requestURI = request.getRequestURI();
|
String requestURI = request.getRequestURI();
|
||||||
|
String msg=e.getMessage();
|
||||||
|
if (StringUtils.hasText(msg)) {
|
||||||
|
if (msg.contains(BODY_ERROR)){
|
||||||
|
return AjaxResult.error("post请求body参数不能为空");
|
||||||
|
}
|
||||||
|
if (msg.contains(DATA_ERROR)){
|
||||||
|
return AjaxResult.error("数据长度过长");
|
||||||
|
}
|
||||||
|
}
|
||||||
log.error("请求地址'{}',发生未知异常.", requestURI, e);
|
log.error("请求地址'{}',发生未知异常.", requestURI, e);
|
||||||
return AjaxResult.error(e.getMessage());
|
return AjaxResult.error(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
@ -94,17 +107,34 @@ public class GlobalExceptionHandler
|
||||||
return AjaxResult.error(e.getMessage());
|
return AjaxResult.error(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param e
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(NumberFormatException.class)
|
||||||
|
public AjaxResult numberFormatException(NumberFormatException e)
|
||||||
|
{
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
System.err.println(e.getMessage());
|
||||||
|
return AjaxResult.error(HttpStatus.FORBIDDEN, "请求参数不正确");
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 自定义验证异常
|
* 自定义验证异常
|
||||||
*/
|
*/
|
||||||
@ExceptionHandler(BindException.class)
|
@ExceptionHandler(BindException.class)
|
||||||
public AjaxResult handleBindException(BindException e)
|
public AjaxResult handleBindException(BindException e)
|
||||||
{
|
{
|
||||||
log.error(e.getMessage(), e);
|
|
||||||
String message = e.getAllErrors().get(0).getDefaultMessage();
|
String message = e.getAllErrors().get(0).getDefaultMessage();
|
||||||
|
System.err.println(message);
|
||||||
|
assert message != null;
|
||||||
|
if(message.contains(NumberFormatException)){
|
||||||
|
return AjaxResult.error(HttpStatus.FORBIDDEN, "请求参数不正确");
|
||||||
|
}
|
||||||
return AjaxResult.error(message);
|
return AjaxResult.error(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 自定义验证异常
|
* 自定义验证异常
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,11 @@
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jsoup</groupId>
|
||||||
|
<artifactId>jsoup</artifactId>
|
||||||
|
<version>1.9.2</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- SpringCloud Loadbalancer -->
|
<!-- SpringCloud Loadbalancer -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ public class AuthWriteUtils {
|
||||||
public static List<String> getBlackUrl(){
|
public static List<String> getBlackUrl(){
|
||||||
List<String> whiteUrl=new ArrayList<>();
|
List<String> whiteUrl=new ArrayList<>();
|
||||||
whiteUrl.add("/bmw/**");
|
whiteUrl.add("/bmw/**");
|
||||||
|
whiteUrl.add("/file/file/ynRealName/**");
|
||||||
return whiteUrl;
|
return whiteUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
package com.bonus.gateway.config;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
|
import org.springframework.web.server.WebFilter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author HeiZi
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class ContextPathConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnProperty("server.servlet.context-path")
|
||||||
|
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||||
|
public WebFilter contextPathWebFilter(ServerProperties serverProperties){
|
||||||
|
String contextPath = serverProperties.getServlet().getContextPath();
|
||||||
|
return (serverWebExchange, webFilterChain) ->{
|
||||||
|
ServerHttpRequest request = serverWebExchange.getRequest();
|
||||||
|
String requestPath = request.getURI().getPath();
|
||||||
|
|
||||||
|
if(requestPath.contains(contextPath)){
|
||||||
|
String newPath = requestPath.replaceFirst(contextPath+"/", "");
|
||||||
|
ServerHttpRequest newRequest = request.mutate()
|
||||||
|
.path(newPath).build();
|
||||||
|
return webFilterChain.filter(serverWebExchange.mutate()
|
||||||
|
.request(newRequest)
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
}else {
|
||||||
|
throw new ResponseStatusException(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -19,6 +19,7 @@ import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
import org.springframework.web.server.ServerWebExchange;
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
|
@ -131,6 +132,18 @@ public class AuthFilter implements GlobalFilter, Ordered
|
||||||
{
|
{
|
||||||
token = token.replaceFirst(TokenConstants.PREFIX, StringUtils.EMPTY);
|
token = token.replaceFirst(TokenConstants.PREFIX, StringUtils.EMPTY);
|
||||||
}
|
}
|
||||||
|
if(StringUtils.isEmpty(token)){
|
||||||
|
String hed="token";
|
||||||
|
String nl="null";
|
||||||
|
MultiValueMap<String, String> tokens= request.getQueryParams();
|
||||||
|
token = request.getHeaders().getFirst(TokenConstants.TOKEN_HEAD);
|
||||||
|
if(tokens.get(hed)!=null && !tokens.get(hed).isEmpty()){
|
||||||
|
token =tokens.get("token").get(0);
|
||||||
|
if(nl.equals(token)){
|
||||||
|
token=null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
package com.bonus.gateway.xss;
|
||||||
|
|
||||||
|
|
||||||
|
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||||
|
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.core.io.buffer.DataBuffer;
|
||||||
|
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
import reactor.core.publisher.Flux;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author:
|
||||||
|
* @Description: 这个过滤器解决body不能重复读的问题,为后续的XssRequestGlobalFilter重写post|put请求的body做准备
|
||||||
|
* @Date:
|
||||||
|
* <p>
|
||||||
|
* 没把body的内容放到attribute中去,因为从attribute取出body内容还是需要强转成 Flux<DataBuffer>,然后转换成String,和直接读取body没有什么区别
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class CacheBodyGlobalFilter implements Ordered, GlobalFilter {
|
||||||
|
@Override
|
||||||
|
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
||||||
|
HttpMethod method = exchange.getRequest().getMethod();
|
||||||
|
String contentType = exchange.getRequest().getHeaders().getFirst(HttpHeaders.CONTENT_TYPE);
|
||||||
|
if (method == HttpMethod.POST || method == HttpMethod.PUT) {
|
||||||
|
if (MediaType.APPLICATION_FORM_URLENCODED_VALUE.equalsIgnoreCase(contentType)
|
||||||
|
|| MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(contentType)
|
||||||
|
|| MediaType.APPLICATION_JSON_UTF8_VALUE.equals(contentType)) {
|
||||||
|
return DataBufferUtils.join(exchange.getRequest().getBody())
|
||||||
|
.flatMap(dataBuffer -> {
|
||||||
|
DataBufferUtils.retain(dataBuffer);
|
||||||
|
Flux<DataBuffer> cachedFlux = Flux
|
||||||
|
.defer(() -> Flux.just(dataBuffer.slice(0, dataBuffer.readableByteCount())));
|
||||||
|
ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(
|
||||||
|
exchange.getRequest()) {
|
||||||
|
@Override
|
||||||
|
public Flux<DataBuffer> getBody() {
|
||||||
|
return cachedFlux;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return chain.filter(exchange.mutate().request(mutatedRequest).build());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return chain.filter(exchange);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrder() {
|
||||||
|
return Ordered.HIGHEST_PRECEDENCE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,124 @@
|
||||||
|
package com.bonus.gateway.xss;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONArray;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import org.jsoup.Jsoup;
|
||||||
|
import org.jsoup.nodes.Document;
|
||||||
|
import org.jsoup.safety.Whitelist;
|
||||||
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author:
|
||||||
|
* @Description: xss过滤工具
|
||||||
|
* @Date:
|
||||||
|
*/
|
||||||
|
public class XssCleanRuleUtils {
|
||||||
|
|
||||||
|
//xss过滤规则(对于script、src及加载事件和弹窗事件的代码块)
|
||||||
|
private final static Pattern[] scriptPatterns = {
|
||||||
|
Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE),
|
||||||
|
Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
|
||||||
|
Pattern.compile("</script>", Pattern.CASE_INSENSITIVE),
|
||||||
|
Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
|
||||||
|
Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
|
||||||
|
Pattern.compile("expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
|
||||||
|
Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE),
|
||||||
|
Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE),
|
||||||
|
Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL)
|
||||||
|
};
|
||||||
|
|
||||||
|
//非富文本的
|
||||||
|
public static String xssClean(String value) {
|
||||||
|
if (value != null) {
|
||||||
|
value = value.replaceAll("\0|\n|\r", "");
|
||||||
|
for (Pattern pattern : scriptPatterns) {
|
||||||
|
value = pattern.matcher(value).replaceAll("");
|
||||||
|
}
|
||||||
|
value = value.replaceAll("<", "<").replaceAll(">", ">");
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//富文本的
|
||||||
|
public static String xssClean2(String value) {
|
||||||
|
if (value != null) {
|
||||||
|
value = value.replaceAll("\0|\n|\r", "");
|
||||||
|
for (Pattern pattern : scriptPatterns) {
|
||||||
|
value = pattern.matcher(value).replaceAll("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//自定义的json白名单
|
||||||
|
private static final ClassPathResource jsoupWhiteListPathRes = new ClassPathResource("/json/xssWhiteList.json");
|
||||||
|
//配置过滤化参数, 不对代码进行格式化
|
||||||
|
private static final Document.OutputSettings outputSettings = new Document.OutputSettings().prettyPrint(false);
|
||||||
|
//富文本的(使用了Jsoup)
|
||||||
|
public static String xssRichTextClean(String value) {
|
||||||
|
// 创建一个自定义的白名单,基于Jsoup的默认白名单
|
||||||
|
Whitelist customWhitelist = Whitelist.basic();
|
||||||
|
InputStream whiteConfig = null;
|
||||||
|
try {
|
||||||
|
whiteConfig = jsoupWhiteListPathRes.getInputStream();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
if (whiteConfig == null) {
|
||||||
|
throw new RuntimeException("读取jsoup xss 白名单文件失败");
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
JSONObject whiteListJson = JSON.parseObject(whiteConfig, JSONObject.class);
|
||||||
|
|
||||||
|
//添加标签 addTags
|
||||||
|
JSONArray addTagsJsonArr = whiteListJson.getJSONArray("addTags");
|
||||||
|
String[] addTagsArr = addTagsJsonArr.toArray(new String[0]);
|
||||||
|
customWhitelist.addTags(addTagsArr);
|
||||||
|
|
||||||
|
|
||||||
|
//添加属性 addAttributes
|
||||||
|
JSONArray addAttrJsonArr = whiteListJson.getJSONArray("addAttributes");
|
||||||
|
Iterator<Object> iter = addAttrJsonArr.iterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
JSONObject attrJsonObj = (JSONObject) iter.next();
|
||||||
|
String tag = attrJsonObj.getString("tag");
|
||||||
|
JSONArray attrJsonArr = attrJsonObj.getJSONArray("attributes");
|
||||||
|
String[] attrArr = attrJsonArr.toArray(new String[0]);
|
||||||
|
customWhitelist.addAttributes(tag, attrArr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//添加 addProtocols
|
||||||
|
JSONArray addProtoJsonArr = whiteListJson.getJSONArray("addProtocols");
|
||||||
|
iter = addProtoJsonArr.iterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
JSONObject attrJsonObj = (JSONObject) iter.next();
|
||||||
|
String tag = attrJsonObj.getString("tag");
|
||||||
|
String attribute = attrJsonObj.getString("attribute");
|
||||||
|
JSONArray protoJsonArr = attrJsonObj.getJSONArray("protocols");
|
||||||
|
String[] protocolArr = protoJsonArr.toArray(new String[0]);
|
||||||
|
customWhitelist.addProtocols(tag, attribute, protocolArr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
value =Jsoup.clean(value, "", customWhitelist, outputSettings);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,201 @@
|
||||||
|
package com.bonus.gateway.xss;
|
||||||
|
import com.bonus.common.core.utils.StringUtils;
|
||||||
|
import com.bonus.gateway.config.properties.XssProperties;
|
||||||
|
import io.netty.buffer.ByteBufAllocator;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||||
|
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.core.io.buffer.DataBuffer;
|
||||||
|
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||||
|
import org.springframework.core.io.buffer.NettyDataBufferFactory;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
|
import reactor.core.publisher.Flux;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.nio.CharBuffer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
/**
|
||||||
|
* @Author:
|
||||||
|
* @Description: 自定义防XSS攻击网关全局过滤器
|
||||||
|
* @Date:
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class XssRequestGlobalFilter implements GlobalFilter, Ordered {
|
||||||
|
@Autowired
|
||||||
|
private XssProperties xss;
|
||||||
|
private Logger logger = LoggerFactory.getLogger(XssRequestGlobalFilter.class);
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param exchange
|
||||||
|
* @param chain
|
||||||
|
* @return
|
||||||
|
*
|
||||||
|
* get请求参考spring cloud gateway自带过滤器:
|
||||||
|
* @see org.springframework.cloud.gateway.filter.factory.AddRequestParameterGatewayFilterFactory
|
||||||
|
*
|
||||||
|
* post请求参考spring cloud gateway自带过滤器:
|
||||||
|
* @see org.springframework.cloud.gateway.filter.factory.rewrite.ModifyRequestBodyGatewayFilterFactory
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain){
|
||||||
|
// grab configuration from Config object
|
||||||
|
logger.info("----自定义防XSS攻击网关全局过滤器生效----");
|
||||||
|
String path = exchange.getRequest().getPath().toString();
|
||||||
|
ServerHttpRequest serverHttpRequest = exchange.getRequest();
|
||||||
|
HttpMethod method = serverHttpRequest.getMethod();
|
||||||
|
String contentType = serverHttpRequest.getHeaders().getFirst(HttpHeaders.CONTENT_TYPE);
|
||||||
|
|
||||||
|
Boolean postFlag = (method == HttpMethod.POST || method == HttpMethod.PUT) &&
|
||||||
|
(MediaType.APPLICATION_FORM_URLENCODED_VALUE.equalsIgnoreCase(contentType) || MediaType.APPLICATION_JSON_VALUE.equals(contentType) || MediaType.APPLICATION_JSON_UTF8_VALUE.equals(contentType));
|
||||||
|
|
||||||
|
// get 请求, 参考的是 org.springframework.cloud.gateway.filter.factory.AddRequestParameterGatewayFilterFactory
|
||||||
|
if (method == HttpMethod.GET) {
|
||||||
|
URI uri = exchange.getRequest().getURI();
|
||||||
|
|
||||||
|
String rawQuery = uri.getRawQuery();
|
||||||
|
if (StringUtils.isBlank(rawQuery)){
|
||||||
|
return chain.filter(exchange);
|
||||||
|
}
|
||||||
|
rawQuery = XssCleanRuleUtils.xssClean(rawQuery);
|
||||||
|
try {
|
||||||
|
URI newUri = UriComponentsBuilder.fromUri(uri)
|
||||||
|
.replaceQuery(rawQuery)
|
||||||
|
.build(true)
|
||||||
|
.toUri();
|
||||||
|
|
||||||
|
ServerHttpRequest request = exchange.getRequest().mutate()
|
||||||
|
.uri(newUri).build();
|
||||||
|
return chain.filter(exchange.mutate().request(request).build());
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("get请求清理xss攻击异常", e);
|
||||||
|
throw new IllegalStateException("Invalid URI query: \"" + rawQuery + "\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//post请求时,如果是文件上传之类的请求,不修改请求消息体
|
||||||
|
else if (postFlag){
|
||||||
|
// 参考的是 org.springframework.cloud.gateway.filter.factory.AddRequestParameterGatewayFilterFactory
|
||||||
|
|
||||||
|
//从请求里获取Post请求体
|
||||||
|
String bodyStr = resolveBodyFromRequest(serverHttpRequest);
|
||||||
|
// 这种处理方式,必须保证post请求时,原始post表单必须有数据过来,不然会报错
|
||||||
|
if (StringUtils.isBlank(bodyStr)) {
|
||||||
|
logger.error("请求异常:{} POST请求必须传递参数", serverHttpRequest.getURI().getRawPath());
|
||||||
|
ServerHttpResponse response = exchange.getResponse();
|
||||||
|
response.setStatusCode(HttpStatus.BAD_REQUEST);
|
||||||
|
byte[] bytes = "{\"code\":400,\"msg\":\"post data error\"}".getBytes(StandardCharsets.UTF_8);
|
||||||
|
DataBuffer buffer = response.bufferFactory().wrap(bytes);
|
||||||
|
return response.writeWith(Mono.just(buffer));
|
||||||
|
}
|
||||||
|
//白名单处理(看业务需求)
|
||||||
|
String url = exchange.getRequest().getURI().getPath();
|
||||||
|
boolean containsTarget =StringUtils.matches(url, xss.getExcludeUrls());
|
||||||
|
if (containsTarget) {
|
||||||
|
//bodyStr = XssCleanRuleUtils.xssRichTextClean(bodyStr);
|
||||||
|
bodyStr = XssCleanRuleUtils.xssClean2(bodyStr);
|
||||||
|
} else {
|
||||||
|
bodyStr = XssCleanRuleUtils.xssClean(bodyStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
URI uri = serverHttpRequest.getURI();
|
||||||
|
URI newUri = UriComponentsBuilder.fromUri(uri).build(true).toUri();
|
||||||
|
ServerHttpRequest request = exchange.getRequest().mutate().uri(newUri).build();
|
||||||
|
DataBuffer bodyDataBuffer = stringBuffer(bodyStr);
|
||||||
|
Flux<DataBuffer> bodyFlux = Flux.just(bodyDataBuffer);
|
||||||
|
|
||||||
|
// 定义新的消息头
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.putAll(exchange.getRequest().getHeaders());
|
||||||
|
|
||||||
|
// 由于修改了传递参数,需要重新设置CONTENT_LENGTH,长度是字节长度,不是字符串长度
|
||||||
|
int length = bodyStr.getBytes().length;
|
||||||
|
headers.remove(HttpHeaders.CONTENT_LENGTH);
|
||||||
|
headers.setContentLength(length);
|
||||||
|
|
||||||
|
// 设置CONTENT_TYPE
|
||||||
|
if (StringUtils.isNotBlank(contentType)) {
|
||||||
|
headers.set(HttpHeaders.CONTENT_TYPE, contentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 由于post的body只能订阅一次,由于上面代码中已经订阅过一次body。所以要再次封装请求到request才行,不然会报错请求已经订阅过
|
||||||
|
request = new ServerHttpRequestDecorator(request) {
|
||||||
|
@Override
|
||||||
|
public HttpHeaders getHeaders() {
|
||||||
|
long contentLength = headers.getContentLength();
|
||||||
|
HttpHeaders httpHeaders = new HttpHeaders();
|
||||||
|
httpHeaders.putAll(super.getHeaders());
|
||||||
|
if (contentLength > 0) {
|
||||||
|
httpHeaders.setContentLength(contentLength);
|
||||||
|
} else {
|
||||||
|
// this causes a 'HTTP/1.1 411 Length Required' on httpbin.org
|
||||||
|
httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
|
||||||
|
}
|
||||||
|
return httpHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Flux<DataBuffer> getBody() {
|
||||||
|
return bodyFlux;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//封装request,传给下一级
|
||||||
|
request.mutate().header(HttpHeaders.CONTENT_LENGTH, Integer.toString(bodyStr.length()));
|
||||||
|
return chain.filter(exchange.mutate().request(request).build());
|
||||||
|
} else {
|
||||||
|
return chain.filter(exchange);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrder() {
|
||||||
|
return -90;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从Flux<DataBuffer>中获取字符串的方法
|
||||||
|
* @return 请求体
|
||||||
|
*/
|
||||||
|
private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest) {
|
||||||
|
//获取请求体
|
||||||
|
Flux<DataBuffer> body = serverHttpRequest.getBody();
|
||||||
|
AtomicReference<String> bodyRef = new AtomicReference<>();
|
||||||
|
body.subscribe(buffer -> {
|
||||||
|
CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
|
||||||
|
DataBufferUtils.release(buffer);
|
||||||
|
bodyRef.set(charBuffer.toString());
|
||||||
|
});
|
||||||
|
//获取request body
|
||||||
|
return bodyRef.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字符串转DataBuffer
|
||||||
|
* @param value
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private DataBuffer stringBuffer(String value) {
|
||||||
|
byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
|
||||||
|
NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
|
||||||
|
DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
|
||||||
|
buffer.write(bytes);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
package com.bonus.gateway.xss;
|
||||||
|
import com.bonus.common.core.utils.StringUtils;
|
||||||
|
import com.bonus.gateway.config.properties.XssProperties;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.reactivestreams.Publisher;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||||
|
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.core.io.buffer.DataBuffer;
|
||||||
|
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||||
|
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||||
|
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
import reactor.core.publisher.Flux;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author:
|
||||||
|
* @Description: 重写Response,防止xss攻击
|
||||||
|
* @Date:
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class XssResponseGlobalFilter implements Ordered, GlobalFilter {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private XssProperties xss;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
||||||
|
//获取请求url
|
||||||
|
String path = exchange.getRequest().getPath().toString();
|
||||||
|
|
||||||
|
ServerHttpResponse originalResponse = exchange.getResponse();
|
||||||
|
DataBufferFactory bufferFactory = originalResponse.bufferFactory();
|
||||||
|
ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
|
||||||
|
@Override
|
||||||
|
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
|
||||||
|
String contentType = getDelegate().getHeaders().getFirst(HttpHeaders.CONTENT_TYPE);
|
||||||
|
Boolean flag = MediaType.APPLICATION_JSON_VALUE.equals(contentType) || MediaType.APPLICATION_JSON_UTF8_VALUE.equals(contentType);
|
||||||
|
if (body instanceof Flux && flag) {
|
||||||
|
Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
|
||||||
|
return super.writeWith(fluxBody.buffer().map(dataBuffer -> {
|
||||||
|
//如果响应过大,会进行截断,出现乱码,
|
||||||
|
//然后看api DefaultDataBufferFactory有个join方法可以合并所有的流,乱码的问题解决
|
||||||
|
DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
|
||||||
|
DataBuffer join = null;
|
||||||
|
try {
|
||||||
|
join = dataBufferFactory.join(dataBuffer);
|
||||||
|
byte[] content = new byte[join.readableByteCount()];
|
||||||
|
join.read(content);
|
||||||
|
//释放掉内存
|
||||||
|
DataBufferUtils.release(join);
|
||||||
|
String result = new String(content, Charset.forName("UTF-8"));
|
||||||
|
//logger.info("result:"+result);
|
||||||
|
//若为带有富文本的接口,走富文本xss过滤
|
||||||
|
String url = exchange.getRequest().getURI().getPath();
|
||||||
|
boolean containsTarget = StringUtils.matches(url, xss.getExcludeUrls());
|
||||||
|
|
||||||
|
if (containsTarget) {
|
||||||
|
//result = XssCleanRuleUtils.xssRichTextClean(result);
|
||||||
|
result = XssCleanRuleUtils.xssClean2(result);
|
||||||
|
} else {
|
||||||
|
//result就是response的值,对result进行去XSS
|
||||||
|
result = XssCleanRuleUtils.xssClean(result);
|
||||||
|
}
|
||||||
|
byte[] uppedContent = new String(result.getBytes(), Charset.forName("UTF-8")).getBytes();
|
||||||
|
return bufferFactory.wrap(uppedContent);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 处理异常,记录日志等
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
if (join != null) {
|
||||||
|
//释放掉内存
|
||||||
|
DataBufferUtils.release(join);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
// if body is not a flux. never got there.
|
||||||
|
return super.writeWith(body);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// replace response with decorator
|
||||||
|
return chain.filter(exchange.mutate().response(decoratedResponse).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrder() {
|
||||||
|
return -50;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -188,7 +188,11 @@
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- SpringBoot Actuator -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.java-websocket</groupId>
|
<groupId>org.java-websocket</groupId>
|
||||||
<artifactId>Java-WebSocket</artifactId>
|
<artifactId>Java-WebSocket</artifactId>
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,12 @@ public class PlanDataConfig {
|
||||||
/**
|
/**
|
||||||
* url地址
|
* url地址
|
||||||
*/
|
*/
|
||||||
public String winUrl = "http://192.168.0.14:1918/ynPlan";
|
public String winUrl = "http://192.168.0.14:9100/ynRealName/ynPlan";
|
||||||
|
//、public String winUrl = "http://192.168.0.14:1918/ynPlan";
|
||||||
// public String linUrl = "http://112.29.103.165:1918/ynPlan";
|
// public String linUrl = "http://112.29.103.165:1918/ynPlan";
|
||||||
public String linUrl = "http://192.168.0.14:1918/ynPlan";
|
// public String linUrl = "http://192.168.0.14:1918/ynPlan";
|
||||||
|
|
||||||
|
|
||||||
|
public String linUrl = "http://192.168.0.14:9100/ynRealName/ynPlan";
|
||||||
/**
|
/**
|
||||||
* 保存token的key
|
* 保存token的key
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ function filePreview(url) {
|
||||||
if (~url.indexOf("http")) {
|
if (~url.indexOf("http")) {
|
||||||
path = url;
|
path = url;
|
||||||
} else {
|
} else {
|
||||||
path = fileUrl + url;
|
path = fileUrl + url+"?token="+Authorization;
|
||||||
}
|
}
|
||||||
console.log("url:", path);
|
console.log("url:", path);
|
||||||
let fileToken = generateToken();
|
let fileToken = generateToken();
|
||||||
|
|
|
||||||
|
|
@ -108,9 +108,9 @@ function showLoginInfo() {
|
||||||
url = ctxPath + "/img/avatars/yn.png";
|
url = ctxPath + "/img/avatars/yn.png";
|
||||||
}
|
}
|
||||||
|
|
||||||
url = domain + url;
|
|
||||||
} else {
|
} else {
|
||||||
url = domain + "/statics" + url;
|
url = domain + "/ynRealName/bmw/statics" + url;
|
||||||
}
|
}
|
||||||
var img = $(".admin-header-user img");
|
var img = $(".admin-header-user img");
|
||||||
img.attr("src", url);
|
img.attr("src", url);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
var ctxPath = getContextPath();
|
|
||||||
var currentHostname = window.location.hostname;
|
|
||||||
let IP_URL="http://127.0.0.1:9100/ynRealName"
|
let IP_URL="http://127.0.0.1:9100/ynRealName"
|
||||||
|
var ctxPath = IP_URL+"/bmw";
|
||||||
|
var currentHostname = window.location.hostname;
|
||||||
|
|
||||||
// //测试
|
// //测试
|
||||||
// var loginPath = "http://" + currentHostname + ":9200";
|
// var loginPath = "http://" + currentHostname + ":9200";
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ function findImg(){
|
||||||
if(data.code==200 && list.length>0){
|
if(data.code==200 && list.length>0){
|
||||||
for(var i=0;i<list.length;i++){
|
for(var i=0;i<list.length;i++){
|
||||||
html+='<div class="photoDiv">';
|
html+='<div class="photoDiv">';
|
||||||
html+='<img src="'+fileUrl + "/"+list[i].photoPath+'" />';
|
html+='<img src="'+fileUrl + "/"+list[i].photoPath+"?token="+Authorization+ '" />';
|
||||||
html+='<span>上传人:</span><sapn>'+list[i].name+'</sapn><br/>';
|
html+='<span>上传人:</span><sapn>'+list[i].name+'</sapn><br/>';
|
||||||
html+='<span>上传时间:</span><sapn>'+list[i].addTime+'</sapn><br/>';
|
html+='<span>上传时间:</span><sapn>'+list[i].addTime+'</sapn><br/>';
|
||||||
html+='</div>';
|
html+='</div>';
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ function findImg(){
|
||||||
if(data.code==200 && list.length>0){
|
if(data.code==200 && list.length>0){
|
||||||
for(var i=0;i<list.length;i++){
|
for(var i=0;i<list.length;i++){
|
||||||
html+='<div class="photoDiv">';
|
html+='<div class="photoDiv">';
|
||||||
html+='<img src="'+fileUrl + "/"+list[i].photoPath+'" />';
|
html+='<img src="'+fileUrl + "/"+list[i].photoPath+"?token="+Authorization+'" />';
|
||||||
html+='<span>上传人:</span><sapn>'+list[i].name+'</sapn><br/>';
|
html+='<span>上传人:</span><sapn>'+list[i].name+'</sapn><br/>';
|
||||||
html+='<span>上传时间:</span><sapn>'+list[i].addTime+'</sapn><br/>';
|
html+='<span>上传时间:</span><sapn>'+list[i].addTime+'</sapn><br/>';
|
||||||
html+='</div>';
|
html+='</div>';
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ function printPhoto(){
|
||||||
path = filePreviewPath + "/" + url;
|
path = filePreviewPath + "/" + url;
|
||||||
}
|
}
|
||||||
// for(var i=0;i<list.length;i++){
|
// for(var i=0;i<list.length;i++){
|
||||||
html+='<img data-original="'+path+'" src="' + path + '" />';
|
html+='<img data-original="'+path+'" src="' + path +"?token="+Authorization + '" />';
|
||||||
// }
|
// }
|
||||||
$("#photoDiv").append(html);
|
$("#photoDiv").append(html);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,11 @@ function findContractDetails(idNumber,id){
|
||||||
var obj=data.data;
|
var obj=data.data;
|
||||||
var bean=obj.bean;
|
var bean=obj.bean;
|
||||||
if(bean !=null){
|
if(bean !=null){
|
||||||
var faceUrl=fileUrl + "/"+bean.faceUrl;//人脸照片路径
|
var faceUrl=fileUrl + "/"+bean.faceUrl+"?token="+Authorization;//人脸照片路径
|
||||||
var shortMessage=bean.shortMessage;//短信信息
|
var shortMessage=bean.shortMessage;//短信信息
|
||||||
var message=bean.message;//验证码
|
var message=bean.message;//验证码
|
||||||
var messageTime=bean.messageTime;//验证码时间
|
var messageTime=bean.messageTime;//验证码时间
|
||||||
var videoUrl=fileUrl + "/"+bean.videoUrl;//视频路径
|
var videoUrl=fileUrl + "/"+bean.videoUrl+"?token="+Authorization;//视频路径
|
||||||
|
|
||||||
$("#faceUrl").attr("src",faceUrl);
|
$("#faceUrl").attr("src",faceUrl);
|
||||||
$("#shortMessage").text(shortMessage);
|
$("#shortMessage").text(shortMessage);
|
||||||
|
|
|
||||||
|
|
@ -1094,7 +1094,7 @@ function setData(data) {
|
||||||
htmlCardPath += '<div class="handle" style="margin-top: -28px" data-idx="wageCard_' + i + '">'
|
htmlCardPath += '<div class="handle" style="margin-top: -28px" data-idx="wageCard_' + i + '">'
|
||||||
htmlCardPath += '<i class="layui-icon layui-icon-delete" style="position: relative;top: 30px;left: 30px; font-size: 20px;color: red" data-idx="wageCard_' + i + '"></i>'
|
htmlCardPath += '<i class="layui-icon layui-icon-delete" style="position: relative;top: 30px;left: 30px; font-size: 20px;color: red" data-idx="wageCard_' + i + '"></i>'
|
||||||
htmlCardPath += '</div>'
|
htmlCardPath += '</div>'
|
||||||
htmlCardPath += '<img src="' + result + '" file="' + fileUrl +"/"+ wageCardPath[i] + '" data-index="wageCard_' + i + '" style="height: 100px;width: 100px;margin-right: 10px" class="layui-upload-img ">'
|
htmlCardPath += '<img src="' + result+"?token="+Authorization + '" file="' + fileUrl +"/"+ wageCardPath[i] + '" data-index="wageCard_' + i + '" style="height: 100px;width: 100px;margin-right: 10px" class="layui-upload-img ">'
|
||||||
htmlCardPath += '<div><span>' + (wageCardName[wageCardName.length - 1].length > 8 ? (wageCardName[wageCardName.length - 1].substr(0, 8) + "..") : wageCardName[wageCardName.length - 1]) + '</span></div>'
|
htmlCardPath += '<div><span>' + (wageCardName[wageCardName.length - 1].length > 8 ? (wageCardName[wageCardName.length - 1].substr(0, 8) + "..") : wageCardName[wageCardName.length - 1]) + '</span></div>'
|
||||||
htmlCardPath += '</div>'
|
htmlCardPath += '</div>'
|
||||||
htmlCardPath += '</div>'
|
htmlCardPath += '</div>'
|
||||||
|
|
|
||||||
|
|
@ -172,7 +172,7 @@ function view() {
|
||||||
html += '<img style="width: 250px;height: 250px;" src="'+data[i]+'">';
|
html += '<img style="width: 250px;height: 250px;" src="'+data[i]+'">';
|
||||||
}else{
|
}else{
|
||||||
let x = fileUrl + "/" + data[i];
|
let x = fileUrl + "/" + data[i];
|
||||||
html += '<img style="width: 250px;height: 250px;" src="'+x+'">';
|
html += '<img style="width: 250px;height: 250px;" src="'+x+"?token="+Authorization+'">';
|
||||||
}
|
}
|
||||||
$("#view1").append(html);
|
$("#view1").append(html);
|
||||||
document.getElementById("view1").ondblclick= function () {
|
document.getElementById("view1").ondblclick= function () {
|
||||||
|
|
@ -184,7 +184,7 @@ function view() {
|
||||||
html += '<img style="width: 250px;height: 250px;" src="'+data[i]+'">';
|
html += '<img style="width: 250px;height: 250px;" src="'+data[i]+'">';
|
||||||
}else{
|
}else{
|
||||||
let x = fileUrl + "/" + data[i];
|
let x = fileUrl + "/" + data[i];
|
||||||
html += '<img style="width: 250px;height: 250px;" src="'+x+'">';
|
html += '<img style="width: 250px;height: 250px;" src="'+x+"?token="+Authorization+'">';
|
||||||
}
|
}
|
||||||
$("#view2").append(html);
|
$("#view2").append(html);
|
||||||
document.getElementById("view2").ondblclick= function () {
|
document.getElementById("view2").ondblclick= function () {
|
||||||
|
|
@ -196,7 +196,7 @@ function view() {
|
||||||
html += '<img style="width: 250px;height: 250px;" src="'+data[i]+'">';
|
html += '<img style="width: 250px;height: 250px;" src="'+data[i]+'">';
|
||||||
}else{
|
}else{
|
||||||
let x = fileUrl + "/" + data[i];
|
let x = fileUrl + "/" + data[i];
|
||||||
html += '<img style="width: 250px;height: 250px;" src="'+x+'">';
|
html += '<img style="width: 250px;height: 250px;" src="'+x+"?token="+Authorization+'">';
|
||||||
}
|
}
|
||||||
$("#view3").append(html);
|
$("#view3").append(html);
|
||||||
document.getElementById("view3").ondblclick= function () {
|
document.getElementById("view3").ondblclick= function () {
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ function viewImg(idNumber) {
|
||||||
html += '<img style="width: 250px;height: 250px;" src="'+data[i]+'">';
|
html += '<img style="width: 250px;height: 250px;" src="'+data[i]+'">';
|
||||||
}else{
|
}else{
|
||||||
let x = fileUrl + "/" + data[i];
|
let x = fileUrl + "/" + data[i];
|
||||||
html += '<img style="width: 250px;height: 250px;" src="'+x+'">';
|
html += '<img style="width: 250px;height: 250px;" src="'+x+"?token="+Authorization+'">';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$("#imgView").append(html);
|
$("#imgView").append(html);
|
||||||
|
|
|
||||||
|
|
@ -495,25 +495,25 @@ function setData(data) {
|
||||||
$("#preview1").css("display", "");
|
$("#preview1").css("display", "");
|
||||||
var demo1 = $("#demo1");
|
var demo1 = $("#demo1");
|
||||||
var html = '';
|
var html = '';
|
||||||
html += '<img newPhoto="1" src="' + path1 + '" id="1" name="1" ondblclick="delPhoto(1)" style="height: 80px;width: 80px;margin-right: 10px" class="layui-upload-img ">';
|
html += '<img newPhoto="1" src="' + path1+"?token="+Authorization + '" id="1" name="1" ondblclick="delPhoto(1)" style="height: 80px;width: 80px;margin-right: 10px" class="layui-upload-img ">';
|
||||||
demo1.append(html);
|
demo1.append(html);
|
||||||
|
|
||||||
$("#preview2").css("display", "");
|
$("#preview2").css("display", "");
|
||||||
var demo2 = $("#demo2");
|
var demo2 = $("#demo2");
|
||||||
var html = '';
|
var html = '';
|
||||||
html += '<img newPhoto="1" src="' + path2 + '" id="2" name="2" ondblclick="delPhoto(2)" style="height: 80px;width: 80px;margin-right: 10px" class="layui-upload-img ">';
|
html += '<img newPhoto="1" src="' + path2+"?token="+Authorization + '" id="2" name="2" ondblclick="delPhoto(2)" style="height: 80px;width: 80px;margin-right: 10px" class="layui-upload-img ">';
|
||||||
demo2.append(html);
|
demo2.append(html);
|
||||||
|
|
||||||
$("#preview3").css("display", "");
|
$("#preview3").css("display", "");
|
||||||
var demo3 = $("#demo3");
|
var demo3 = $("#demo3");
|
||||||
var html = '';
|
var html = '';
|
||||||
html += '<img newPhoto="1" src="' + path3 + '" id="3" name="3" ondblclick="delPhoto(3)" style="height: 80px;width: 80px;margin-right: 10px" class="layui-upload-img ">';
|
html += '<img newPhoto="1" src="' + path3 +"?token="+Authorization+ '" id="3" name="3" ondblclick="delPhoto(3)" style="height: 80px;width: 80px;margin-right: 10px" class="layui-upload-img ">';
|
||||||
demo3.append(html);
|
demo3.append(html);
|
||||||
|
|
||||||
$("#preview4").css("display", "");
|
$("#preview4").css("display", "");
|
||||||
var demo4 = $("#demo4");
|
var demo4 = $("#demo4");
|
||||||
var html = '';
|
var html = '';
|
||||||
html += '<img newPhoto="1" src="' + path4 + '" id="4" name="4" ondblclick="delPhoto(4)" style="height: 80px;width: 80px;margin-right: 10px" class="layui-upload-img ">';
|
html += '<img newPhoto="1" src="' + path4+"?token="+Authorization + '" id="4" name="4" ondblclick="delPhoto(4)" style="height: 80px;width: 80px;margin-right: 10px" class="layui-upload-img ">';
|
||||||
demo4.append(html);
|
demo4.append(html);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ function setData() {
|
||||||
localStorage.setItem('contractTypes', data.contractBean.contractType);
|
localStorage.setItem('contractTypes', data.contractBean.contractType);
|
||||||
}
|
}
|
||||||
//人脸照片
|
//人脸照片
|
||||||
$('.basicContentLeft>img').attr('src', fileUrl + '/' + data.facePhoto);
|
$('.basicContentLeft>img').attr('src', fileUrl + '/' + data.facePhoto+"?token="+Authorization);
|
||||||
//红绿灯
|
//红绿灯
|
||||||
if(Number(data.lightStatus) == 0){
|
if(Number(data.lightStatus) == 0){
|
||||||
$('.basicContentRight>img').attr('src','../../../../img/work/indexScreen/redLamp.png')
|
$('.basicContentRight>img').attr('src','../../../../img/work/indexScreen/redLamp.png')
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,10 @@
|
||||||
<scope>system</scope>
|
<scope>system</scope>
|
||||||
<systemPath>${project.basedir}/lib/aspose-words-15.8.0-jdk16.jar</systemPath>
|
<systemPath>${project.basedir}/lib/aspose-words-15.8.0-jdk16.jar</systemPath>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>aspose</groupId>
|
<groupId>aspose</groupId>
|
||||||
<artifactId>aspose-slide</artifactId>
|
<artifactId>aspose-slide</artifactId>
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,11 @@
|
||||||
<version>2.2.1</version>
|
<version>2.2.1</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- SpringBoot Actuator -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
|
</dependency>
|
||||||
<!-- <dependency>-->
|
<!-- <dependency>-->
|
||||||
<!-- <groupId>com.bonus</groupId>-->
|
<!-- <groupId>com.bonus</groupId>-->
|
||||||
<!-- <artifactId>real_name_file</artifactId>-->
|
<!-- <artifactId>real_name_file</artifactId>-->
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue