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 |
@ -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.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 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