前言
Asp.Net Core Identity 是Asp.Net Core 的重要组成部分,他为 Asp.Net Core 甚至其他 .Net Core 应用程序提供了一个简单易用且易于扩展的基础用户管理系统框架。它包含了基本的用户、角色、第三方登录、Claim等功能,使用 Identity Server 4 可以为其轻松扩展 OpenId connection 和 Oauth 2.0 相关功能。网上已经有大量相关文章介绍,不过这还不是 Asp.Net Core Identity 的全部,其中一个就是隐私数据保护。
正文
乍一看,隐私数据保护是个什么东西,感觉好像知道,但又说不清楚。确实这个东西光说很难解释清楚,那就直接上图:
这是用户表的一部分,有没有发现问题所在?用户名和 Email 字段变成了一堆看不懂的东西。仔细看会发现这串乱码好像还有点规律:guid + 冒号 +貌似是 base64 编码的字符串,当然这串字符串去在线解码结果还是一堆乱码,比如 id 为 1 的 UserName :svBqhhluYZSiPZVUF4baOQ== 在线解码后是²ðj"htmlcode">
//注册Identity服务(使用EF存储,在EF上下文之后注册) services.AddIdentity<ApplicationUser, ApplicationRole>(options => { //... options.Stores.ProtectPersonalData = true; //在这里启用隐私数据保护 }) //... .AddPersonalDataProtection<AesProtector, AesProtectorKeyRing>(); //在这里配置数据加密器,一旦启用保护,这里必须配置,否则抛出异常
其中的AesProtector 和AesProtectorKeyRing 需要自行实现,微软并没有提供现成的类,至少我没有找到,估计也是这个功能冷门的原因吧。.Neter 都被微软给惯坏了,都是衣来伸手饭来张口。有没有发现AesProtectorKeyRing 中有KeyRing 字样?钥匙串,恭喜你猜对了,guid 就是这个钥匙串中一把钥匙的编号。也就是说如果加密的钥匙被盗,但不是全部被盗,那用户信息还不会全部泄露。微软这一手可真是狠啊!
接下来看看这两个类是什么吧。
AesProtector 是 ILookupProtector 的实现。接口包含两个方法,分别用于加密和解密,返回字符串,参数包含字符串数据和上面那个 guid,当然实际只要是字符串就行, guid 是我个人的选择,生成不重复字符串还是 guid 方便。
AesProtectorKeyRing 则是 ILookupProtectorKeyRing 的实现。接口包含1、获取当前正在使用的钥匙编号的只读属性,用于提供加密钥匙;2、根据钥匙编号获取字符串的索引器(我这里就是原样返回的。。。);3、获取所有钥匙编号的方法。
AesProtector
class AesProtector : ILookupProtector { private readonly object _locker; private readonly Dictionary<string, SecurityUtil.AesProtector> _protectors; private readonly DirectoryInfo _dirInfo; public AesProtector(IWebHostEnvironment environment) { _locker = new object(); _protectors = new Dictionary<string, SecurityUtil.AesProtector>(); _dirInfo = new DirectoryInfo($@"{environment.ContentRootPath}\App_Data\AesDataProtectionKey"); } public string Protect(string keyId, string data) { if (data.IsNullOrEmpty()) { return data; } CheckOrCreateProtector(keyId); return _protectors[keyId].Protect(Encoding.UTF8.GetBytes(data)).ToBase64String(); } public string Unprotect(string keyId, string data) { if (data.IsNullOrEmpty()) { return data; } CheckOrCreateProtector(keyId); return Encoding.UTF8.GetString(_protectors[keyId].Unprotect(data.ToBytesFromBase64String())); } private void CheckOrCreateProtector(string keyId) { if (!_protectors.ContainsKey(keyId)) { lock (_locker) { if (!_protectors.ContainsKey(keyId)) { var fileInfo = _dirInfo.GetFiles().FirstOrDefault(d => d.Name == $@"key-{keyId}.xml") "key")"encryption")"masterKey")"key")"encryption")"iv")"key")"encryption")"BlockSize")"key")"encryption")"KeySize")"key")"encryption")"FeedbackSize")"key")"encryption")"Padding")"key")"encryption")"Mode")"htmlcode">class AesProtectorKeyRing : ILookupProtectorKeyRing { private readonly object _locker; private readonly Dictionary<string, XDocument> _keyRings; private readonly DirectoryInfo _dirInfo; public AesProtectorKeyRing(IWebHostEnvironment environment) { _locker = new object(); _keyRings = new Dictionary<string, XDocument>(); _dirInfo = new DirectoryInfo($@"{environment.ContentRootPath}\App_Data\AesDataProtectionKey"); ReadKeys(_dirInfo); } public IEnumerable<string> GetAllKeyIds() { return _keyRings.Keys; } public string CurrentKeyId => NewestActivationKey(DateTimeOffset.Now)"key")"id")"key")"id")".xml")) { using (var stream = fileInfo.OpenRead()) { XDocument xmlDoc = XDocument.Load(stream); _keyRings.TryAdd(xmlDoc.Element("key")"id")"key")"activationDate")"key")"expirationDate")"key")"activationDate")"key")"expirationDate")"1.0", "utf-8", "yes"); XElement key = new XElement("key"); key.SetAttributeValue("id", masterKeyId); key.SetAttributeValue("version", 1); XElement creationDate = new XElement("creationDate"); creationDate.SetValue(now); XElement activationDate = new XElement("activationDate"); activationDate.SetValue(now); XElement expirationDate = new XElement("expirationDate"); expirationDate.SetValue(now.AddDays(90)); XElement encryption = new XElement("encryption"); encryption.SetAttributeValue("BlockSize", 128); encryption.SetAttributeValue("KeySize", 256); encryption.SetAttributeValue("FeedbackSize", 128); encryption.SetAttributeValue("Padding", PaddingMode.PKCS7); encryption.SetAttributeValue("Mode", CipherMode.CBC); SecurityUtil.AesProtector protector = new SecurityUtil.AesProtector(); XElement masterKey = new XElement("masterKey"); masterKey.SetValue(protector.GenerateKey().ToBase64String()); XElement iv = new XElement("iv"); iv.SetValue(protector.GenerateIV().ToBase64String()); xmlDoc.Add(key); key.Add(creationDate); key.Add(activationDate); key.Add(expirationDate); key.Add(encryption); encryption.Add(masterKey); encryption.Add(iv); xmlDoc.Save( $@"{dirInfo.FullName}\key-{masterKeyId}.xml"); _keyRings.Add(masterKeyId, xmlDoc); return xmlDoc; } return NewestActivationKey(now); } } return NewestActivationKey(now); } private XDocument NewestActivationKey(DateTimeOffset now) { return _keyRings.Where(item => DateTimeOffset.Parse(item.Value.Element("key")"activationDate")"key")"expirationDate")"key")"expirationDate")"text-align: center">本文地址:https://www.cnblogs.com/coredx/p/12210232.html
完整源代码:Github
里面有各种小东西,这只是其中之一,不嫌弃的话可以Star一下。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
RTX 5090要首发 性能要翻倍!三星展示GDDR7显存
三星在GTC上展示了专为下一代游戏GPU设计的GDDR7内存。
首次推出的GDDR7内存模块密度为16GB,每个模块容量为2GB。其速度预设为32 Gbps(PAM3),但也可以降至28 Gbps,以提高产量和初始阶段的整体性能和成本效益。
据三星表示,GDDR7内存的能效将提高20%,同时工作电压仅为1.1V,低于标准的1.2V。通过采用更新的封装材料和优化的电路设计,使得在高速运行时的发热量降低,GDDR7的热阻比GDDR6降低了70%。
更新日志
- 关淑怡.2009-ERA【星娱乐】【WAV+CUE】
- 林忆莲《关于她的爱情故事》2022新世纪MQA 24K金碟限量版[WAV+CUE]
- 张雨生1993《一天到晚游泳的鱼》台湾G字首版[WAV+CUE][1G]
- 群星《试音五大女声》[WAV+CUE][1G]
- 魔兽世界wlk武器战一键输出宏是什么 wlk武器战一键输出宏介绍
- 魔兽世界wlk狂暴战一键输出宏是什么 wlk狂暴战一键输出宏介绍
- 魔兽世界wlk恶魔术士一键输出宏是什么 wlk恶魔术士一键输出宏介绍
- 医学爱好者狂喜:UP主把医学史做成了格斗游戏!
- PS5 Pro评分解禁!准备升级入手吗?
- 我们盘点了近期火热的国产单机游戏!《琉隐神渡》等 你期待哪款?
- 2019年第12届广州影音展双碟纪念版ADMS2CD[MP3/WAV]
- 黄安《救姻缘》台首版[WAV+CUE]
- 模拟之声慢刻CD《柏林之声4》[正版CD低速原抓WAV+CUE]
- 李宗盛 《李宗盛经典金曲》[WAV+CUE][1G]
- 周华健《粤语精选》[WAV+CUE][1G]