前言
上次,我们介绍了,可以将数值型Id加密成无意义的字符串,但是通过这些字符串又可以反向映射出真实的Id以供内部使用。比如B站的播放链接
/video/BV1xK4y1VXXX
应该就是这种实现方式。
但是,我们希望在 Core Web API实现中使用的还是真实的数值型Id,方便操作;而在对外输入/输出时对Id进行自动加解密转换,保证安全。
类似这样:
//请求/user/WwYQ//id=12345publicUserDtoGet(intid)
那么,应该如何实现呢?
自定义序列化
在输出时,我们需要自动加密Id。
在这里,通过编写一个自定义JsonConverter来实现:
publicclassHashIdJsonConverter:JsonConverter<int>{Hashidshashids=newHashids("公众号MyIO");//加盐publicoverrideintRead(refUtf8JsonReaderreader,TypetypeToConvert,JsonSerializerOptionsoptions){varstr=JsonSerializer.Deserialize<string>(refreader,options);returnhashids.Decode(str)[0];}publicoverridevoidWrite(Utf8JsonWriterwriter,intvalue,JsonSerializerOptionsoptions){JsonSerializer.Serialize(writer,hashids.Encode(value),options);}}
运行程序,发现我们的Id被正常加密:
publicclassUserDto{[JsonConverter(typeof(HashIdJsonConverter))]publicintId{get;set;}publicstringName{get;set;}}[HttpGet]publicIEnumerable<UserDto>Get(){returnnew[]{newUserDto{Id=12345,Name="用户12345"}};}
自定义模型绑定
在输入时,我们需要自动解密Id。
在这里,通过编写一个自定义IModelBinder来实现:
publicclassHashIdModelBinder:IModelBinder{Hashidshashids=newHashids("公众号MyIO");//加盐publicTaskBindModelAsync(ModelBindingContextbindingContext){varmodelName=bindingContext.ModelName;varvalueProviderResult=bindingContext.ValueProvider.GetValue(modelName);varstr=valueProviderResult.FirstValue;bindingContext.Result=ModelBindingResult.Success(hashids.Decode(str)[0]);pletedTask;}}
运行程序,发现我们的Id被正常解密:
[HttpGet("{id}")]publicUserDtoGet([ModelBinder(typeof(HashIdModelBinder))]intid){returnnewUserDto{Id=id,Name="用户"+id};}
结论
在本文中,通过实现自定义序列化和模型绑定,我们实现了 Core Web API使用加密Id,而在内部使用的还是真实的数值型Id。
如果你觉得这篇文章对你有所启发,请关注我的个人公众号”My IO“