前言

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 的全部,其中一个就是隐私数据保护。

正文

乍一看,隐私数据保护是个什么东西,感觉好像知道,但又说不清楚。确实这个东西光说很难解释清楚,那就直接上图:

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">Asp.Net Core Identity 隐私数据保护的实现

Asp.Net Core Identity 隐私数据保护的实现

  本文地址:https://www.cnblogs.com/coredx/p/12210232.html

  完整源代码:Github

  里面有各种小东西,这只是其中之一,不嫌弃的话可以Star一下。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

标签:
Asp.Net,Core,Identity,数据保护,Asp.Net,Core,Identity

免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
狼山资源网 Copyright www.pvsay.com

评论“Asp.Net Core Identity 隐私数据保护的实现”

暂无“Asp.Net Core Identity 隐私数据保护的实现”评论...

《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线

暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。

艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。

《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。