前言
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一下。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
RTX 5090要首发 性能要翻倍!三星展示GDDR7显存
三星在GTC上展示了专为下一代游戏GPU设计的GDDR7内存。
首次推出的GDDR7内存模块密度为16GB,每个模块容量为2GB。其速度预设为32 Gbps(PAM3),但也可以降至28 Gbps,以提高产量和初始阶段的整体性能和成本效益。
据三星表示,GDDR7内存的能效将提高20%,同时工作电压仅为1.1V,低于标准的1.2V。通过采用更新的封装材料和优化的电路设计,使得在高速运行时的发热量降低,GDDR7的热阻比GDDR6降低了70%。
更新日志
- 古典吉他《鲁特琴-BachInspirations巴赫灵感》ThibautGarcia[24Bit/96kHz]
- 刘纬武《睡眠音乐家 缓解疼痛 赫兹白噪音》[320K/MP3][217.2MB]
- 刘纬武《睡眠音乐家 缓解疼痛 赫兹白噪音》[FLAC/分轨][870.69MB]
- 群星1998 《宝丽金最佳电视主题曲》香港首版[WAV+CUE][1.2G]
- 群星1990《群星会·金曲重现》新加坡版[WAV+CUE][1.1G]
- 张惠妹2003《勇敢》[WAV+CUE][1.1G]
- 群星1995《摇滚中国乐势力》首版引进版[WAV+CUE][983M]
- 陈思安《32首酒廊情调》2CD新雅(国际)影碟[WAV+CUE]
- 齐豫潘越云《回声》K2HD[正版原抓WAV+CUE]
- 凤飞飞《我们的主题曲》飞跃制作[正版原抓WAV+CUE]
- 刘嘉亮《亮情歌2》[WAV+CUE][1G]
- 红馆40·谭咏麟《歌者恋歌浓情30年演唱会》3CD[低速原抓WAV+CUE][1.8G]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[320K/MP3][193.25MB]
- 【轻音乐】曼托凡尼乐团《精选辑》2CD.1998[FLAC+CUE整轨]
- 邝美云《心中有爱》1989年香港DMIJP版1MTO东芝首版[WAV+CUE]