对json中指定字段进⾏加密操作
最近开发过程中,遇到⼀个场景。即要在打印⽇志的时候对json中部分字段进⾏加密操作(数据传输时不需要加密)。
⼀下是选定的解决⽅案。
JAVA项⽬:
⼀、使⽤“注解”配合fastjson的“值过滤器”,实现对字段⾃动加密。
1.1 创建⾃定义注解【EncryptionField】。
import java.lang.annotation.*;
/**
* ⽤于标识需要加密的字段
*/
@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
object topublic @interface EncryptionField {
}
1.2 创建⾃定义json过滤器继承⾃ValueFilter【EncryptionFieldFilter】。
import com.alibaba.fastjson.serializer.ValueFilter;
lipse.jgit.util.StringUtils;
import flect.Field;
import java.util.Objects;
/**
* 对使⽤【EncryptionField】标注的字段加密
*/
public class EncryptionFieldFilter implements ValueFilter {
/**
* 加密key
*/
private String encryptKey;
public EncryptionFieldFilter(String encryptKey) {
}
@Override
public Object process(Object object, String name, Object value) {
try {
Field field = Class().getDeclaredField(name);
if (Objects.isNull(value) || String.class != Type() || (Annotation(EncryptionField.class)) == null) {
return value;
}
if (String.class == Type() && StringUtils.String())) {
return value;
}
String(), encryptKey);
} catch (Exception e) {
}
return value;
}
}
1.3 直接使⽤,或者在⽇志aop中使⽤。
⼆、⾃定义⽅法解构json,对设置的字段集合进⾏加密。算是笨⽅法,不过可以处理复杂结构的json,也不⽤将json转为对象就可以操作。
2.1 定义解构⽅法,及要操作的字段集合。因为⽇志经常放在aop中,这⾥把url作为⼊参,每个接⼝对应各⾃的加密节点。
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;import org.apachemons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.*;
@Component
public class JsonEncryptUtil {
// 加密key
@Value("${EncryptionKey}")
private String encryptKey;
// 需要加密的⽇志节点
private static Map<String, List<String>> encryptNodeMap = new HashMap<>(){
{
put("order/submit", Arrays.asList( // 进件接⼝
"customerInfo.name",
"customerInfo.identityNo",
"bile","ditCardNo",
"cardInfo.cashCardNo");
put("order/check", Arrays.asList( // 验证接⼝
"name",
"identityNo"));
}
};
/**
* ⽂本加密(忽略异常)
*
* @param text ⼊参
* @return加密字符串
*/
public String stringEncrypt(String text) {
try {
if (!StringUtils.isBlank(text)) {
text = pt(text, encryptKey);
}
} catch (Exception e) {
text = "⽂本加密异常:" + e.getMessage() + "加密前信息:" + text;
}
return text;
}
/**
* json指定节点加密
*
* @param json ⼊参
* @return加密字符串
*/
public String jsonEncrypt(String url, String json) {
String result = json;
try {
if (!StringUtils.isBlank(json)) {
for (String key : encryptNodeMap.keySet()){
LowerCase().LowerCase())){
result = GetAesJToken(JSON.im()), (key)).toString();
}
}
}
} catch (Exception e) {
result = "⽇志加密异常:" + e.getMessage() + "加密前信息:" + json;
}
return result;
}
/**
* 根据节点逐⼀展开json对象并进⾏加密
*
* @param object ⼊参
* @param nodeList ⼊参
* @return结果
*/
private Object GetAesJToken(Object object, List<String> nodeList) {
// 如果为空,直接返回
if (object == null || nodeList.size() == 0) return object;
JSONObject jsonObject = null;
// 多层节点递归展开,单层节点直接加密
Map<String, List<String>> deepLevelNodes = new HashMap<>();
for (var node : nodeList) {
var nodeArr = Arrays.asList(node.split("\\."));
if (nodeArr.size() > 1) {
if ((0)))
<((0)).ip.utils.StringUtils.join(nodeArr.subList(1, nodeArr.size()), "."));
else
deepLevelNodes.(0), new ArrayList<>(Arrays.ip.utils.StringUtils.join(nodeArr.subList(1, nodeArr.size()), ".")))); } else {
object = JsonNodeToAes(object, node);
}
}
if (deepLevelNodes.size() > 0) {
for (String key : deepLevelNodes.keySet()) {
if (JSON.String())) {
var jObject = JSON.String());
if ((key) != null) {
jObject.put(key, (key), (key)));
}
object = jObject;
}
if (JSON.String())) {
var jArray = JSON.String());
for (int i = 0; i < jArray.size(); i++) {
JSONObject curObject = JSONObject(i);
if (curObject != null && (key) != null) {
jArray.set(i, (key), (key)));
}
}
object = jArray;
}
}
}
return object;
}
/**
* 将确定节点加密
*
* @param object ⼊参
* @param node ⼊参
* @return结果
*/
private Object JsonNodeToAes(Object object, String node) {
if (object == null) return object;
if (JSON.String())) {
var jObject = JSON.String());
if ((node) != null) {
if (JSON.(node).toString())) {
var jArray = JSONArray(node);
for (int i = 0; i < jArray.size(); i++) {
jArray.set(i, (i).toString()));
}
jObject.put(node, jArray);
} else if (!JSON.(node).toString())) {
jObject.put(node, (node).toString()));
}
}
object = jObject;
} else if (JSON.String())) {
var jArray = JSON.String());
for (int i = 0; i < jArray.size(); i++) {
Object curObject = JSONObject(i);
if (curObject != null) {
jArray.set(i, JsonNodeToAes(curObject, node));
}
}
object = jArray;
} else {
object = String());
}
return object;
}
}
2.2 如果打印⽇志在静态⽅法中,可以通过以下⽅式注⼊依赖。正常使⽤的场景就不列举了。public static JsonEncryptUtil jsonEncryptUtil;
@Resource
public void setJsonEncryptUtil(JsonEncryptUtil service) {
jsonEncryptUtil = service;
}
@Setter
public static class ApiLog {
private Long startTime;
private Long endTime;
private Long consumeTime;
private String requestUrl;
private String requestMethod;
private String requestIp;
private String apiClassName;
private String apiMethodName;
private String requestBody;
private String responseBody;
public static ApiLog newInstance() {
return new ApiLog();
}
private ApiLog() {
startTime = System.currentTimeMillis();
}
public void setEndTime(Long endTime) {
}
@Override
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append("耗时:").append(consumeTime).append("ms").append(" , ");
buffer.append("URL:").append(requestUrl).append(" , ");
buffer.append("IP:").append(requestIp).append(" , ");
buffer.append("⽅式:").append(requestMethod).append(" , ");
buffer.append("请求⽅法:").append(apiClassName).append(".").append(apiMethodName).append(" , "); buffer.append("\r\n");
buffer.append("输⼊:").append(jsonEncryptUtil.jsonEncrypt(requestUrl, requestBody));
buffer.append("\r\n");
buffer.append("输出:").append(responseBody);
String();
}
}
.NET 项⽬:
C#的暂不细说了,和java⼀样理解就好。下⾯附上json解构⽅法。
///<summary>
///要加密的⽇志节点(区分⼤⼩写)
///</summary>
public static List<string> aesLogNodes = new List<string> {
"identityNo",
"name",
"oldCashCardNo",
"newCashCardNo",
"mobile",
"data.idNo",
"data.userName",
"bile",
"data.baseInfo.userName",
"data.baseInfo.idNo",
"isterMobile",
};
///<summary>
/// json串指定字段加密
///</summary>
///<param name="json"></param>
///<param name="aesKey"></param>
///<returns></returns>
public static string ToJsonAes(this string json, string aesKey)
{
try
{
var jToken = JsonConvert.DeserializeObject<JToken>(json ?? "");
return GetAesJToken(jToken, aesLogNodes, aesKey).ToJson();
}
catch (System.Exception ex)
{
return $"⽇志加密失败:{ex.Message}。原⽂:{json ?? ""}";
}
}
/
//<summary>
/// json串指定字段加密
///</summary>
///<param name="json"></param>
///<param name="aesKey"></param>
///<returns></returns>
public static string ToJsonAes(this object json, string aesKey)
{
try
{
var jToken = JToken.FromObject(json ?? "");
return GetAesJToken(jToken, aesLogNodes, aesKey).ToJson();
}
catch (System.Exception ex)
{
return $"⽇志加密失败:{ex.Message}。原⽂:{(json ?? "").ToJson()}";
}
}
///<summary>
///根据节点逐⼀展开json对象并进⾏加密
///</summary>
///<param name="jToken"></param>
/
//<param name="nodeList"></param>
///<param name="aesKey"></param>
///<returns></returns>
private static JToken GetAesJToken(JToken jToken, List<string> nodeList, string aesKey)
{
if (jToken == null || jToken.Type == JTokenType.Null || (nodeList?.Count ?? 0) == 0) return jToken;
// 如果当前节点是json字符串格式,直接转为json对象
if (jToken.Type == JTokenType.String && ((jToken.ToString().Trim().StartsWith("{") && jToken.ToString().Trim().EndsWith("}")) || (jToken.ToString().Trim().StartsWith("[") && jToken.ToString().Trim().EndsWith("]"))))
{
jToken = JsonConvert.DeserializeObject<JToken>(jToken.ToString());
}
// 多层节点递归展开,单层节点直接加密
Dictionary<string, List<string>> deepLevelNodes = new Dictionary<string, List<string>>();
foreach (var node in nodeList)
{
var nodeArr = node.Split('.');
if (nodeArr.Length > 1)
{
if (deepLevelNodes.ContainsKey(nodeArr.First()))
deepLevelNodes[nodeArr.First()].Add(string.Join(".", nodeArr.Skip(1)));
else
deepLevelNodes.Add(nodeArr.First(), (new List<string> { string.Join(".", nodeArr.Skip(1)) }));
}
else
{
jToken = JsonNodeToAes(jToken, node, aesKey);
}
}
if (deepLevelNodes.Count > 0)
{
foreach (var deep in deepLevelNodes)
{
if (jToken.Type == JTokenType.Object)
{
if (jToken[deep.Key] != null)
jToken[deep.Key] = GetAesJToken(jToken[deep.Key], deep.Value, aesKey);
}
if (jToken.Type == JTokenType.Array)
{
for (int i = 0; i < jToken.Count(); i++)
{
if (jToken[i][deep.Key] != null)
jToken[i] = GetAesJToken(jToken[i][deep.Key], deep.Value, aesKey);
}
}
}
}
return jToken;
}
///<summary>
///将确定节点加密
///</summary>
///<param name="jToken"></param>
///<param name="node"></param>
/
//<param name="aesKey"></param>
///<returns></returns>
private static JToken JsonNodeToAes(JToken jToken, string node, string aesKey)
{
if (jToken == null) return jToken;
// 如果当前节点是json字符串格式,直接转为json对象
if (jToken.Type == JTokenType.String && ((jToken.ToString().Trim().StartsWith("{") && jToken.ToString().Trim().EndsWith("}")) || (jToken.ToString().Trim().StartsWith("[") && jToken.ToString().Trim().EndsWith("]"))))
{
jToken = JsonConvert.DeserializeObject<JToken>(jToken.ToString());
}
if (jToken.Type == JTokenType.String)
{
jToken = jToken.ToString().AesEncrypts(aesKey, WebModel.Enums.EncryptionType.Aes);
}
if (jToken.Type == JTokenType.Object)
{
if (jToken[node] != null && jToken[node].Type == JTokenType.String)
{
jToken[node] = jToken[node].ToString().AesEncrypts(aesKey, WebModel.Enums.EncryptionType.Aes);
}
if (jToken[node] != null && jToken[node].Type == JTokenType.Array)
{
for (int i = 0; i < jToken[node].Count(); i++)
{
if (jToken[node][i] != null && jToken[node][i].Type == JTokenType.String)
jToken[node][i] = jToken[node][i].ToString().AesEncrypts(aesKey, WebModel.Enums.EncryptionType.Aes);
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论