parent
57490e76ab
commit
8fa20f37f1
@ -0,0 +1,50 @@ |
|||||||
|
package com.unionmed.framework.crypto; |
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.apache.commons.codec.binary.Base64; |
||||||
|
|
||||||
|
import javax.crypto.Cipher; |
||||||
|
import javax.crypto.spec.IvParameterSpec; |
||||||
|
import javax.crypto.spec.SecretKeySpec; |
||||||
|
import java.io.UnsupportedEncodingException; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author ianChen |
||||||
|
* @date 2023/6/21 11:45 |
||||||
|
*/ |
||||||
|
@Slf4j |
||||||
|
public class AES { |
||||||
|
|
||||||
|
private static final String ALGORITHM = "AES"; |
||||||
|
private static final String PADDING = "AES/CBC/ISO10126Padding"; // AES/CBC/PKCS5PADDING
|
||||||
|
|
||||||
|
private static byte[] toUtf8Bytes(String s) throws UnsupportedEncodingException { |
||||||
|
return s.getBytes("UTF-8"); |
||||||
|
} |
||||||
|
|
||||||
|
public static String encrypt(String sk, String iv, String value) { |
||||||
|
try { |
||||||
|
IvParameterSpec ivSpec = new IvParameterSpec(toUtf8Bytes(iv)); |
||||||
|
SecretKeySpec skSpec = new SecretKeySpec(toUtf8Bytes(sk), ALGORITHM); |
||||||
|
Cipher cipher = Cipher.getInstance(PADDING); |
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, skSpec, ivSpec); |
||||||
|
return Base64.encodeBase64String(cipher.doFinal(value.getBytes())); |
||||||
|
} catch (Exception ex) { |
||||||
|
log.error("AES加密失败", ex); |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static String decrypt(String sk, String iv, String val) { |
||||||
|
try { |
||||||
|
IvParameterSpec ivSpec = new IvParameterSpec(toUtf8Bytes(iv)); |
||||||
|
SecretKeySpec skSpec = new SecretKeySpec(toUtf8Bytes(sk), ALGORITHM); |
||||||
|
Cipher cipher = Cipher.getInstance(PADDING); |
||||||
|
cipher.init(Cipher.DECRYPT_MODE, skSpec, ivSpec); |
||||||
|
return new String(cipher.doFinal(Base64.decodeBase64(val))); |
||||||
|
} catch (Exception ex) { |
||||||
|
log.error("AES解密失败", ex); |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -1,64 +0,0 @@ |
|||||||
package com.unionmed.framework.spring.mvc; |
|
||||||
|
|
||||||
import com.unionmed.framework.http.HttpHeaders; |
|
||||||
import com.unionmed.framework.spring.mvc.annotation.ResponsePrototype; |
|
||||||
import com.unionmed.framework.spring.mvc.datatemplate.DataTemplate; |
|
||||||
import com.unionmed.framework.spring.mvc.datatemplate.DataTemplates; |
|
||||||
import com.unionmed.framework.util.ObjectUtils; |
|
||||||
import com.unionmed.framework.spring.mvc.BaseReturn; |
|
||||||
import org.springframework.core.MethodParameter; |
|
||||||
import org.springframework.http.converter.HttpMessageConverter; |
|
||||||
import org.springframework.http.converter.HttpMessageNotWritableException; |
|
||||||
import org.springframework.web.HttpMediaTypeNotAcceptableException; |
|
||||||
import org.springframework.web.context.request.NativeWebRequest; |
|
||||||
import org.springframework.web.method.support.ModelAndViewContainer; |
|
||||||
import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor; |
|
||||||
|
|
||||||
import java.io.IOException; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author ianChen |
|
||||||
* @date 2022/12/16 10:49 |
|
||||||
*/ |
|
||||||
public class ResponseBodyProcessor extends RequestResponseBodyMethodProcessor { |
|
||||||
|
|
||||||
public ResponseBodyProcessor(List<HttpMessageConverter<?>> converters) { |
|
||||||
super(converters); |
|
||||||
} |
|
||||||
|
|
||||||
private Object handleValue(Object returnValue, NativeWebRequest webRequest) { |
|
||||||
String dataTemplateName = webRequest.getHeader(HttpHeaders.X_DATA_TEMPLATE); |
|
||||||
if (ObjectUtils.isEmpty(dataTemplateName)) |
|
||||||
return returnValue; |
|
||||||
|
|
||||||
DataTemplate dataTemplate = DataTemplates.get(dataTemplateName); |
|
||||||
if (null == dataTemplate) |
|
||||||
return returnValue; |
|
||||||
|
|
||||||
return dataTemplate.handle(returnValue); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException { |
|
||||||
if (!hasResponsePrototype(returnType)) { |
|
||||||
if (returnValue == null) { |
|
||||||
returnValue = BaseReturn.suc(); |
|
||||||
} else if (!(returnValue instanceof BaseReturn)) { |
|
||||||
returnValue = BaseReturn.suc(returnValue); |
|
||||||
} |
|
||||||
|
|
||||||
returnValue = handleValue(returnValue, webRequest); |
|
||||||
} |
|
||||||
super.handleReturnValue(returnValue, returnType, mavContainer, webRequest); |
|
||||||
} |
|
||||||
|
|
||||||
private boolean hasResponsePrototype(MethodParameter returnType) { |
|
||||||
return returnType.getAnnotatedElement().getAnnotation(ResponsePrototype.class) != null; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean supportsReturnType(MethodParameter returnType) { |
|
||||||
return returnType.getDeclaringClass().getName().startsWith("com.unionmed"); |
|
||||||
} |
|
||||||
} |
|
@ -1,8 +0,0 @@ |
|||||||
package com.unionmed.framework.spring.mvc; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author ianChen |
|
||||||
* @date 2022/12/16 16:23 |
|
||||||
*/ |
|
||||||
public interface ResponseTemplate { |
|
||||||
} |
|
@ -0,0 +1,37 @@ |
|||||||
|
package com.unionmed.framework.spring.mvc.response; |
||||||
|
|
||||||
|
import org.springframework.core.MethodParameter; |
||||||
|
import org.springframework.http.converter.HttpMessageConverter; |
||||||
|
import org.springframework.http.converter.HttpMessageNotWritableException; |
||||||
|
import org.springframework.web.HttpMediaTypeNotAcceptableException; |
||||||
|
import org.springframework.web.context.request.NativeWebRequest; |
||||||
|
import org.springframework.web.method.support.ModelAndViewContainer; |
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author ianChen |
||||||
|
* @date 2022/12/16 10:49 |
||||||
|
*/ |
||||||
|
public class ResponseBodyProcessor extends RequestResponseBodyMethodProcessor { |
||||||
|
|
||||||
|
private final ResponseBodyProcessorChain responseBodyProcessorChain; |
||||||
|
|
||||||
|
public ResponseBodyProcessor(List<HttpMessageConverter<?>> converters, ResponseBodyProcessorChain responseBodyProcessorChain) { |
||||||
|
super(converters); |
||||||
|
this.responseBodyProcessorChain = responseBodyProcessorChain; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException { |
||||||
|
returnValue = responseBodyProcessorChain.handler(returnValue, returnType, mavContainer, webRequest); |
||||||
|
super.handleReturnValue(returnValue, returnType, mavContainer, webRequest); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean supportsReturnType(MethodParameter returnType) { |
||||||
|
return returnType.getDeclaringClass().getName().startsWith("com.unionmed"); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,43 @@ |
|||||||
|
package com.unionmed.framework.spring.mvc.response; |
||||||
|
|
||||||
|
import com.unionmed.framework.spring.mvc.response.interceptor.ResponseBodyInterceptor; |
||||||
|
import com.unionmed.framework.util.ObjectUtils; |
||||||
|
import org.springframework.core.MethodParameter; |
||||||
|
import org.springframework.web.context.request.NativeWebRequest; |
||||||
|
import org.springframework.web.method.support.ModelAndViewContainer; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Collections; |
||||||
|
import java.util.Comparator; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author ianChen |
||||||
|
* @date 2023/6/25 15:10 |
||||||
|
*/ |
||||||
|
public class ResponseBodyProcessorChain { |
||||||
|
|
||||||
|
private List<ResponseBodyInterceptor> interceptors = new ArrayList<>(0); |
||||||
|
|
||||||
|
public Object handler(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) { |
||||||
|
if (ObjectUtils.notEmpty(interceptors)) { |
||||||
|
for (ResponseBodyInterceptor interceptor : interceptors) { |
||||||
|
returnValue = interceptor.handleReturnValue(returnValue, returnType, mavContainer, webRequest); |
||||||
|
} |
||||||
|
} |
||||||
|
return returnValue; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean add(ResponseBodyInterceptor... interceptors) { |
||||||
|
if (ObjectUtils.isEmpty(interceptors)) return false; |
||||||
|
|
||||||
|
for (ResponseBodyInterceptor interceptor : interceptors) { |
||||||
|
if (interceptor != null) { |
||||||
|
this.interceptors.add(interceptor); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Collections.sort(this.interceptors, Comparator.comparingInt(ResponseBodyInterceptor::getOrder)); |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
@ -1,4 +1,4 @@ |
|||||||
package com.unionmed.framework.spring.mvc.datatemplate; |
package com.unionmed.framework.spring.mvc.response.datatemplate; |
||||||
|
|
||||||
/** |
/** |
||||||
* @author ianChen |
* @author ianChen |
@ -0,0 +1,42 @@ |
|||||||
|
package com.unionmed.framework.spring.mvc.response.datatemplate; |
||||||
|
|
||||||
|
import com.unionmed.framework.http.HttpHeaders; |
||||||
|
import com.unionmed.framework.spring.mvc.BaseReturn; |
||||||
|
import com.unionmed.framework.spring.mvc.annotation.ResponsePrototype; |
||||||
|
import com.unionmed.framework.spring.mvc.response.interceptor.ResponseBodyInterceptor; |
||||||
|
import com.unionmed.framework.util.ObjectUtils; |
||||||
|
import org.springframework.core.MethodParameter; |
||||||
|
import org.springframework.core.annotation.Order; |
||||||
|
import org.springframework.web.context.request.NativeWebRequest; |
||||||
|
import org.springframework.web.method.support.ModelAndViewContainer; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author ianChen |
||||||
|
* @date 2023/6/25 10:29 |
||||||
|
*/ |
||||||
|
public class DataTemplateResponseBodyInterceptor implements ResponseBodyInterceptor { |
||||||
|
|
||||||
|
@Override |
||||||
|
public Object handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) { |
||||||
|
if (returnType.getAnnotatedElement().getAnnotation(ResponsePrototype.class) != null) |
||||||
|
return returnValue; |
||||||
|
|
||||||
|
if (returnValue == null) { |
||||||
|
returnValue = BaseReturn.suc(); |
||||||
|
} else if (!BaseReturn.class.isAssignableFrom(returnValue.getClass())) { |
||||||
|
returnValue = BaseReturn.suc(returnValue); |
||||||
|
} |
||||||
|
|
||||||
|
String dataTemplate = webRequest.getHeader(HttpHeaders.X_DATA_TEMPLATE); |
||||||
|
if (ObjectUtils.isEmpty(dataTemplate)) |
||||||
|
return returnValue; |
||||||
|
|
||||||
|
DataTemplate template = DataTemplates.get(dataTemplate); |
||||||
|
return null == template ? returnValue : template.handle(returnValue); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getOrder() { |
||||||
|
return 9; |
||||||
|
} |
||||||
|
} |
@ -1,4 +1,4 @@ |
|||||||
package com.unionmed.framework.spring.mvc.datatemplate; |
package com.unionmed.framework.spring.mvc.response.datatemplate; |
||||||
|
|
||||||
import com.unionmed.framework.bean.BeanFactory; |
import com.unionmed.framework.bean.BeanFactory; |
||||||
import com.unionmed.framework.util.ObjectUtils; |
import com.unionmed.framework.util.ObjectUtils; |
@ -1,4 +1,4 @@ |
|||||||
package com.unionmed.framework.spring.mvc.datatemplate; |
package com.unionmed.framework.spring.mvc.response.datatemplate; |
||||||
|
|
||||||
import com.unionmed.framework.spring.mvc.BaseReturn; |
import com.unionmed.framework.spring.mvc.BaseReturn; |
||||||
import org.springframework.stereotype.Component; |
import org.springframework.stereotype.Component; |
@ -0,0 +1,88 @@ |
|||||||
|
package com.unionmed.framework.spring.mvc.response.interceptor; |
||||||
|
|
||||||
|
import cn.hutool.json.JSONUtil; |
||||||
|
import com.alibaba.fastjson.JSON; |
||||||
|
import com.alibaba.fastjson.JSONObject; |
||||||
|
import com.unionmed.framework.crypto.AES; |
||||||
|
import com.unionmed.framework.http.HttpHeaders; |
||||||
|
import com.unionmed.framework.spring.mvc.BaseReturn; |
||||||
|
import com.unionmed.framework.spring.mvc.BaseReturnUtils; |
||||||
|
import com.unionmed.framework.util.Generators; |
||||||
|
import com.unionmed.framework.util.ObjectUtils; |
||||||
|
import org.springframework.core.MethodParameter; |
||||||
|
import org.springframework.core.env.Environment; |
||||||
|
import org.springframework.web.context.request.NativeWebRequest; |
||||||
|
import org.springframework.web.method.support.ModelAndViewContainer; |
||||||
|
|
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
/** |
||||||
|
* 加密拦截 |
||||||
|
* |
||||||
|
* @author ianChen |
||||||
|
* @date 2023/6/25 10:33 |
||||||
|
*/ |
||||||
|
public class EncryptionResponseBodyInterceptor implements ResponseBodyInterceptor { |
||||||
|
|
||||||
|
private final Environment environment; |
||||||
|
private final String RESOURCE_PREFIX = "unionmed.web.response.body.crypt.aes"; |
||||||
|
private final String SK_KEY = RESOURCE_PREFIX + ".sk"; |
||||||
|
private final String ENABLED_KEY = RESOURCE_PREFIX + ".enabled"; |
||||||
|
private final boolean enabled; |
||||||
|
private final String sk; |
||||||
|
|
||||||
|
public EncryptionResponseBodyInterceptor(Environment environment) { |
||||||
|
this.environment = environment; |
||||||
|
if (ObjectUtils.equalsIgnore(environment.getProperty(ENABLED_KEY), "true")) { |
||||||
|
this.sk = environment.getProperty(SK_KEY); |
||||||
|
if (ObjectUtils.isEmpty(sk)) |
||||||
|
throw new NullPointerException("AES SecretKey is empty"); |
||||||
|
this.enabled = true; |
||||||
|
} else { |
||||||
|
this.enabled = false; |
||||||
|
this.sk = null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Object handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) { |
||||||
|
if (!this.enabled || returnValue == null) return null; |
||||||
|
|
||||||
|
String value = webRequest.getHeader(HttpHeaders.X_DATA_CRYPT_E); |
||||||
|
if (ObjectUtils.equalsIgnore(value, HttpHeaders.X_DATA_CRYPT_E_VALUE_TRUE)) { |
||||||
|
returnValue = handleReturnValue(sk, Generators.randomMix(16), returnValue); |
||||||
|
} |
||||||
|
|
||||||
|
return returnValue; |
||||||
|
} |
||||||
|
|
||||||
|
private Object handleReturnValue(String sk, String iv, Object returnValue) { |
||||||
|
if (returnValue instanceof BaseReturn) { |
||||||
|
BaseReturn br = (BaseReturn) returnValue; |
||||||
|
if (br.getData() != null) { |
||||||
|
br.setData(handleReturnValue(sk, iv, br.getData())); |
||||||
|
return returnValue; |
||||||
|
} |
||||||
|
} else if (returnValue instanceof String) { |
||||||
|
String str = (String) returnValue; |
||||||
|
if (JSONUtil.isJsonObj(str)) { |
||||||
|
return handleReturnValue(sk, iv, JSONObject.parseObject(str)); |
||||||
|
} |
||||||
|
} else if (returnValue instanceof JSONObject) { |
||||||
|
JSONObject jObject = (JSONObject) returnValue; |
||||||
|
if (BaseReturnUtils.isBaseReturnFormat(jObject)) { |
||||||
|
jObject.put("data", handleReturnValue(sk, iv, jObject.get("data"))); |
||||||
|
return jObject; |
||||||
|
} |
||||||
|
} else if (returnValue instanceof Map) { |
||||||
|
return handleReturnValue(sk, iv, new JSONObject((Map<String, Object>) returnValue)); |
||||||
|
} |
||||||
|
|
||||||
|
return iv + AES.encrypt(sk, iv, JSON.toJSONString(returnValue)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getOrder() { |
||||||
|
return 8; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,27 @@ |
|||||||
|
package com.unionmed.framework.spring.mvc.response.interceptor; |
||||||
|
|
||||||
|
import org.springframework.core.MethodParameter; |
||||||
|
import org.springframework.core.Ordered; |
||||||
|
import org.springframework.web.context.request.NativeWebRequest; |
||||||
|
import org.springframework.web.method.support.ModelAndViewContainer; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author ianChen |
||||||
|
* @date 2023/6/25 10:27 |
||||||
|
*/ |
||||||
|
public interface ResponseBodyInterceptor extends Ordered { |
||||||
|
|
||||||
|
/** |
||||||
|
* @param returnValue |
||||||
|
* @param returnType |
||||||
|
* @param mavContainer |
||||||
|
* @param webRequest |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
Object handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest); |
||||||
|
|
||||||
|
@Override |
||||||
|
default int getOrder() { |
||||||
|
return 10; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue