.Net中如何优雅的对输出字段进行脱敏 您所在的位置:网站首页 手机号怎么脱敏 .Net中如何优雅的对输出字段进行脱敏

.Net中如何优雅的对输出字段进行脱敏

2024-06-18 03:17| 来源: 网络整理| 查看: 265

背景:

在平常工作中,我们会遇到很多场景,需要对提供给前端(Web、APP)或三方的接口中敏感字段(如:姓名、身份证、手机号、银行卡等)进行脱敏处理。相信多数程序员同学最常用的方式是写一个脱敏的Util类:xxx.RealName = DesensitizationUtil.replaceRealName(xxx.RealName ); 相信这个大家都不陌生,但作为一个有追求的程序员咱必须得找一个比较“牛逼”看起来舒服点的写法。正好最近项目中有这样的需求,并且在网上.Net资料中这类文章很少,于是写了这个文章和大家分享。

 

思路:

鉴于之前在网上看过的一些资料,我决定通过在字段上加脱敏修饰类和自定义序列化处理,使用.Net特性Attribute结合Json.Net中的JsonConverter来实现。在需要脱敏的对象加自定义Converter修饰类:CommonReplaceConvter,在需要脱敏的字段上加自定义修改类:RegexReplaceAttribute。最后在序列化JsonConvert.SerializeObject方法执行时,会执行CommonReplaceConvter并获取字段中自定义属性RegexReplaceAttribute,如果存在则进行脱敏处理并重新赋值给当前字段。

 

实现:

1、定义RegexReplaceAttribute修饰类,包含2个属性(正则表达式,规则表达式)

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace JsonDemo.JsonNet 8 { 9 [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] 10 public sealed class RegexReplaceAttribute : Attribute 11 { 12 public RegexReplaceAttribute(string regexp, string replacer) 13 { 14 this.Regexp = regexp; 15 this.Replacer = replacer; 16 } 17 18 public string Regexp { get; set; } 19 public string Replacer { get; set; } 20 } 21 }

 

 

2、定义CommonReplaceConvter类,继承抽象类JsonConverter,重写CanConvert、ReadJson、WriteJson方法

1 using Newtonsoft.Json; 2 using Newtonsoft.Json.Linq; 3 using System; 4 using System.Collections.Generic; 5 using System.Linq; 6 using System.Reflection; 7 using System.Runtime.CompilerServices; 8 using System.Text; 9 using System.Text.RegularExpressions; 10 using System.Threading.Tasks; 11 12 namespace JsonDemo.JsonNet 13 { 14 public class CommonReplaceConvter : JsonConverter 15 { 16 public override bool CanConvert(Type objectType) 17 { 18 return true; 19 } 20 21 public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 22 { 23 //获取父对象类型 24 object rootObject = Activator.CreateInstance(objectType); 25 //从JsonReader中获取当前对象的值 26 JToken data = JToken.ReadFrom(reader); 27 object propValue; 28 //对属性进行遍历 29 foreach (var token in data) 30 { 31 //获取属性信息 32 PropertyInfo propInfo = rootObject.GetType().GetProperty 33 (token.Path, BindingFlags.IgnoreCase | BindingFlags.Public | 34 BindingFlags.Instance); 35 //当前字段可写 36 if (propInfo.CanWrite) 37 { 38 var tk = token as JProperty; 39 propValue = tk.Value; 40 if (tk.Value is JObject) 41 { 42 JValue val = tk.Value.SelectToken("value") as JValue; 43 propValue = val.Value; 44 } 45 46 //获取正则替换自定义修饰类 47 var regexReplaceAttr = propInfo.GetCustomAttribute(); 48 //当前字段存在修饰类,进行正则替换脱敏 49 if (regexReplaceAttr != null && propValue != null) 50 { 51 propValue = Regex.Replace(propValue.ToString(), regexReplaceAttr.Regexp, regexReplaceAttr.Replacer); 52 } 53 54 propInfo.SetValue(rootObject, Convert.ChangeType(propValue, propInfo.PropertyType.UnderlyingSystemType), null); 55 } 56 } 57 return rootObject; 58 } 59 60 public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 61 { 62 var jo = new JObject(); 63 var type = value.GetType(); 64 foreach (PropertyInfo propInfo in type.GetProperties()) 65 { 66 if (propInfo.CanRead) 67 { 68 object propVal = propInfo.GetValue(value, null); 69 jo.Add(propInfo.Name, JToken.FromObject(propVal ?? string.Empty, serializer)); 70 } 71 } 72 jo.WriteTo(writer); 73 } 74 } 75 }

 

3、在需要脱敏的类上增加修饰特性[JsonConverter(typeof(CommonReplaceConvter))],脱敏的字段上增加修饰特性[RegexReplace(@"(\d{3})(\d{4})(\d{4})", "$1****$3")]

1 using JsonDemo.JsonNet; 2 using Newtonsoft.Json; 3 using System; 4 using System.Collections.Generic; 5 using System.Linq; 6 using System.Text; 7 using System.Threading.Tasks; 8 9 namespace JsonDemo.Models 10 { 11 [JsonConverter(typeof(CommonReplaceConvter))] 12 public class UserInfo2 13 { 14 public int UserId { get; set; } 15 16 [RegexReplace(@"(\d{3})(\d{4})(\d{4})", "$1****$3")] 17 public string Phone { get; set; } 18 19 [RegexReplace(@"(\d{4})(\d{10})([\dxX]{4})", "$1**********$3")] 20 public string IdNumber { get; set; } 21 22 [RegexReplace(@"([\u4e00-\u9fa5])([\u4e00-\u9fa5]+)", "*$2")] 23 public string RealName { get; set; } 24 } 25 }

 

示例:

1 using JsonDemo.Models; 2 using Newtonsoft.Json; 3 using System; 4 using System.Collections.Generic; 5 using System.Diagnostics; 6 using System.Linq; 7 using System.Text; 8 using System.Threading.Tasks; 9 10 namespace JsonDemo 11 { 12 class Program 13 { 14 static void Main(string[] args) 15 { 16 var json = "{\"UserId\":123,\"Phone\":\"13512345678\",\"IdNumber\":\"11010119900307061X\",\"RealName\":\"张三\"}"; 17 var user1 = JsonConvert.DeserializeObject(json); 18 var st = new Stopwatch(); 19 st.Start(); 20 Console.WriteLine("user1:" + JsonConvert.SerializeObject(user1)); 21 st.Stop(); 22 Console.WriteLine("user1耗时:" + st.ElapsedMilliseconds + "\n\n"); 23 24 var user2 = JsonConvert.DeserializeObject(json); 25 st.Restart(); 26 Console.WriteLine("user2:" + JsonConvert.SerializeObject(user2)); 27 st.Stop(); 28 Console.WriteLine("user2耗时:" + st.ElapsedMilliseconds + "\n\n"); 29 30 Console.ReadLine(); 31 } 32 } 33 }

 

 

总结:

以上为此方案实现的全过程,怎么样是不是比某某某Util方法要优雅很多。扩展性是不是也更好,有其他特殊脱敏逻辑的时候,可以继续自定义Attribute特性,并在Converter中获取特性进行业务逻辑处理,适用场景也比较多(日志脱敏打印、根据权限脱敏等)

 

说明:

软件环境(.NetFramework 4.6 + Newtonsoft.Json 6.0.8)

由于此处为演示Demo,真实项目中如Asp.Net Web Api 或 .Net Core Web Api中需要将Json序列化器指定为Json.Net,否则脱敏会不生效

以上代码有些反射的地方未加缓存优化,此处仅提供一种思路,实际场景中对性能有要求的可自行考虑优化



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有