<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          《ASP.NET Core 與 RESTful API 開(kāi)發(fā)實(shí)戰(zhàn)》-- (第8章)-- 讀書(shū)筆記(下)

          共 11890字,需瀏覽 24分鐘

           ·

          2020-08-19 04:02

          第 8 章 認(rèn)證和安全

          8.3 HTTPS

          HTTP 協(xié)議能夠在客戶端和服務(wù)器之間傳遞信息,特點(diǎn)是以明文的方式發(fā)送內(nèi)容,并不提供任何方式的數(shù)據(jù)加密

          為了解決 HTTP 協(xié)議這一缺陷,需要使用另一種協(xié)議:HTTPS,它在 HTTP 的基礎(chǔ)上加入了安全套接層 SSL 協(xié)議

          SSL 層依靠證書(shū)來(lái)驗(yàn)證服務(wù)器的身份,并在傳輸層為瀏覽器和服務(wù)器之間的通信加密

          自 ASP.NET Core 2.1 起,在默認(rèn)情況下,所創(chuàng)建的 ASP.NET Core 應(yīng)用程序都啟用了 HTTPS

          public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
          {
          if (env.IsDevelopment())
          {
          app.UseDeveloperExceptionPage();
          }
          else
          {
          app.UseHsts();
          }

          app.UseHttpsRedirection();

          。。。
          }

          在 launchSettings.json 配置文件中也包含了 HTTPS 端口配置

          "sslPort": 44304

          "applicationUrl": "https://localhost:5001;http://localhost:5000",

          HTTPS 重定向中間件會(huì)將所有的非安全請(qǐng)求重定向到安全的 HTTPS 協(xié)議上,它使用 HttpsRedirectionOptions 對(duì)象中的配置來(lái)進(jìn)行重定向

          namespace Microsoft.AspNetCore.HttpsPolicy
          {
          public class HttpsRedirectionOptions
          {
          public int RedirectStatusCode { get; set; } = 307;// 用于設(shè)置重定向時(shí)的狀態(tài)碼,默認(rèn)值307 Temporary Redirect

          public int? HttpsPort { get; set; }// 重定向URL中要用到的端口號(hào)
          }
          }

          若要修改重定向選項(xiàng),則可以在 ConfigureServices 方法中添加如下代碼

          services.AddHttpsRedirection(option =>
          {
          option.RedirectStatusCode = StatusCodes.Status307TemporaryRedirect;
          option.HttpsPort = 5001;
          }
          );

          HSTS 中間件使用 HSTS 來(lái)進(jìn)一步保證客戶端和服務(wù)器之間數(shù)據(jù)傳輸?shù)陌踩?,作用是?qiáng)制客戶端使用 HTTPS 與服務(wù)器建立鏈接,實(shí)現(xiàn)方式是在響應(yīng)消息中添加 Strict-Transport-Security 消息頭,該消息頭可以使瀏覽器在接下來(lái)指定的時(shí)間內(nèi),強(qiáng)制當(dāng)前域名只能通過(guò) HTTPS 進(jìn)行訪問(wèn)

          services.AddHsts(options =>
          {
          options.IncludeSubDomains = true;// 表明該網(wǎng)站所有子域名也必須通過(guò)HTTPS協(xié)議來(lái)訪問(wèn)
          options.Preload = true;// 可選參數(shù),只有在申請(qǐng)將當(dāng)前網(wǎng)站的域名加入瀏覽器內(nèi)置列表時(shí),才需要使用它
          options.MaxAge = TimeSpan.FromDays(120);// 指定時(shí)間內(nèi),這個(gè)網(wǎng)站必須通過(guò)HTTPS協(xié)議來(lái)訪問(wèn)
          options.ExcludedHosts.Clear();// 由于本地服務(wù)器不會(huì)使用HTTPS,為了查看效果,需要清除所有被排除的主機(jī)列表
          });

          之所以應(yīng)該在正式環(huán)境中使用 HSTS,是因?yàn)?HSTS 配置會(huì)被瀏覽器緩存,因此不建議在開(kāi)發(fā)環(huán)境中使用 HSTS

          8.4 數(shù)據(jù)保護(hù)

          Web 應(yīng)用程序通常需要存儲(chǔ)安全敏感數(shù)據(jù),ASP.NET Core 提供了數(shù)據(jù)保護(hù) API,用于加密和解密數(shù)據(jù)功能

          數(shù)據(jù)保護(hù) API 主要包含兩個(gè)接口:IDataProtectionProvider 與 IDataProtector

          IDataProtectionProvider 接口主要用于創(chuàng)建 IDataProtector 類型對(duì)象

          namespace Microsoft.AspNetCore.DataProtection
          {
          public interface IDataProtectionProvider
          {
          IDataProtector CreateProtector(string purpose);
          }
          }

          IDataProtector 接口用于執(zhí)行實(shí)際的數(shù)據(jù)保護(hù)操作

          namespace Microsoft.AspNetCore.DataProtection
          {
          public interface IDataProtector : IDataProtectionProvider
          {
          byte[] Protect(byte[] plaintext);

          byte[] Unprotect(byte[] protectedData);
          }
          }

          為了方便使用上述兩個(gè)接口,在相同的命名空間中還包含了為它們定義的擴(kuò)展方法

          namespace Microsoft.AspNetCore.DataProtection
          {
          public static class DataProtectionCommonExtensions
          {
          public static IDataProtector CreateProtector(
          this IDataProtectionProvider provider,
          IEnumerable<string> purposes)
          {
          if (provider == null)
          throw new ArgumentNullException(nameof (provider));
          if (purposes == null)
          throw new ArgumentNullException(nameof (purposes));
          bool flag = true;
          IDataProtectionProvider protectionProvider = provider;
          foreach (string purpose in purposes)
          {
          if (purpose == null)
          throw new ArgumentException(Resources.DataProtectionExtensions_NullPurposesCollection, nameof (purposes));
          protectionProvider = (IDataProtectionProvider) (protectionProvider.CreateProtector(purpose) ?? CryptoUtil.Fail("CreateProtector returned null."));
          flag = false;
          }
          if (flag)
          throw new ArgumentException(Resources.DataProtectionExtensions_NullPurposesCollection, nameof (purposes));
          return (IDataProtector) protectionProvider;
          }

          public static IDataProtector CreateProtector(
          this IDataProtectionProvider provider,
          string purpose,
          params string[] subPurposes)
          {
          if (provider == null)
          throw new ArgumentNullException(nameof (provider));
          if (purpose == null)
          throw new ArgumentNullException(nameof (purpose));
          IDataProtector provider1 = provider.CreateProtector(purpose);
          if (subPurposes != null && subPurposes.Length != 0)
          provider1 = provider1 != null ? provider1.CreateProtector((IEnumerable<string>) subPurposes) : (IDataProtector) null;
          return provider1 ?? CryptoUtil.Fail("CreateProtector returned null.");
          }

          public static IDataProtectionProvider GetDataProtectionProvider(
          this IServiceProvider services)
          {
          if (services == null)
          throw new ArgumentNullException(nameof (services));
          IDataProtectionProvider service = (IDataProtectionProvider) services.GetService(typeof (IDataProtectionProvider));
          if (service != null)
          return service;
          throw new InvalidOperationException(Resources.FormatDataProtectionExtensions_NoService((object) typeof (IDataProtectionProvider).FullName));
          }

          public static IDataProtector GetDataProtector(
          this IServiceProvider services,
          IEnumerable<string> purposes)
          {
          if (services == null)
          throw new ArgumentNullException(nameof (services));
          if (purposes == null)
          throw new ArgumentNullException(nameof (purposes));
          return services.GetDataProtectionProvider().CreateProtector(purposes);
          }

          public static IDataProtector GetDataProtector(
          this IServiceProvider services,
          string purpose,
          params string[] subPurposes)
          {
          if (services == null)
          throw new ArgumentNullException(nameof (services));
          if (purpose == null)
          throw new ArgumentNullException(nameof (purpose));
          return services.GetDataProtectionProvider().CreateProtector(purpose, subPurposes);
          }

          public static string Protect(this IDataProtector protector, string plaintext)
          {
          if (protector == null)
          throw new ArgumentNullException(nameof (protector));
          if (plaintext == null)
          throw new ArgumentNullException(nameof (plaintext));
          try
          {
          byte[] bytes = EncodingUtil.SecureUtf8Encoding.GetBytes(plaintext);
          return WebEncoders.Base64UrlEncode(protector.Protect(bytes));
          }
          catch (Exception ex) when (ex.RequiresHomogenization())
          {
          throw Error.CryptCommon_GenericError(ex);
          }
          }

          public static string Unprotect(this IDataProtector protector, string protectedData)
          {
          if (protector == null)
          throw new ArgumentNullException(nameof (protector));
          if (protectedData == null)
          throw new ArgumentNullException(nameof (protectedData));
          try
          {
          byte[] protectedData1 = WebEncoders.Base64UrlDecode(protectedData);
          byte[] bytes = protector.Unprotect(protectedData1);
          return EncodingUtil.SecureUtf8Encoding.GetString(bytes);
          }
          catch (Exception ex) when (ex.RequiresHomogenization())
          {
          throw Error.CryptCommon_GenericError(ex);
          }
          }
          }
          }

          前兩個(gè)方法用于根據(jù)多個(gè)目的的字符串來(lái)創(chuàng)建 IDataProtector,后兩個(gè)方法使用 IDataProtector 的 Protect 和 Unprotect 方法能夠接受并返回字符串

          要在程序中使用數(shù)據(jù)保護(hù) API,需要先添加服務(wù)

          services.AddDataProtection();

          之后,在需要的位置,將 IDataProtectionProvider 接口注入即可

          namespace WebApplication1.Controllers
          {
          [Route("api/[controller]")]
          [ApiController]
          public class ValueController : Controller
          {
          private List students = new List();
          public IDataProtectionProvider DataProtectionProvider { get; set; }

          public ValueController(IDataProtectionProvider dataProtectionProvider)
          {
          DataProtectionProvider = dataProtectionProvider;
          students.Add(new Student
          {
          Id = "1",
          Name = "Jim"
          });
          }

          [HttpGet]
          public ActionResult> Get()
          {
          var protector = DataProtectionProvider.CreateProtector("ProtectResourceId");
          var result = students.Select(s => new Student
          {
          Id = protector.Protect(s.Id),// 加密
          Name = s.Name
          });

          return result.ToList();
          }

          [HttpGet]
          public ActionResult Get(string id)
          {
          var protector = DataProtectionProvider.CreateProtector("ProtectResourceId");
          var rawId = protector.Unprotect(id);// 解密
          var targetItem = students.FirstOrDefault(s => s.Id == rawId);
          return new Student {Id = id, Name = targetItem.Name};
          }
          }

          public class Student
          {
          public string Id { get; set; }

          public string Name { get; set; }
          }
          }

          由于 IDataProtector 接口同樣可同于創(chuàng)建 IDataProtector 對(duì)象,因此可以創(chuàng)建具有層次的 IDataProtector 對(duì)象

          var protectorA = DataProtectionProvider.CreateProtector("A");
          var protectorB = protectorA.CreateProtector("B");
          var protectorC = protectorB.CreateProtector("C");

          需要注意的是,在對(duì)數(shù)據(jù)解密時(shí),必須使用與加密時(shí)相同的方式創(chuàng)建的 IDataProtector 對(duì)象

          為了更方便地創(chuàng)建具有層次的 IDataProtector 對(duì)象,可以使用如下 IDataProtectionProvider 接口的擴(kuò)展方法

          DataProtectionProvider.CreateProtector("Parent", "Child");

          如果使用上述 protectorC 對(duì)象加密信息,則可以使用如下方式進(jìn)行解密

          var content = protectorC.Protect("Hello");
          var protector = DataProtectionProvider.CreateProtector("A", "B", "C");
          var rawContent = protector.Unprotect(content);

          使用 protectorC 加密的內(nèi)容,可以使用 CreateProtector("A", "B", "C") 創(chuàng)建的 IDataProtector 進(jìn)行解密。這種具有層次的 IDataProtector 在根據(jù)不同版本或不同用戶保護(hù)數(shù)據(jù)時(shí)非常方便

          var protectV1 = DataProtectionProvider.CreateProtector("DemoApp.ValueController", "v1");
          var protectV2 = DataProtectionProvider.CreateProtector("DemoApp.ValueController", "v2");

          為數(shù)據(jù)加密設(shè)置有效時(shí)間,在 Microsoft.AspNetCore.DataProtection 包中為 IDataProtector 接口定義了一個(gè)擴(kuò)展方法

          public static ITimeLimitedDataProtector ToTimeLimitedDataProtector(
          this IDataProtector protector)
          {
          if (protector == null)
          throw new ArgumentNullException(nameof (protector));
          return protector is ITimeLimitedDataProtector limitedDataProtector ? limitedDataProtector : (ITimeLimitedDataProtector) new TimeLimitedDataProtector(protector);
          }

          該方法能夠?qū)?IDataProtector 對(duì)象轉(zhuǎn)換為 ITimeLimitedDataProtector 類型的對(duì)象,為密文增加有效時(shí)間

          ITimeLimitedDataProtector 接口定義如下

          namespace Microsoft.AspNetCore.DataProtection
          {
          public interface ITimeLimitedDataProtector : IDataProtector, IDataProtectionProvider
          {
          ITimeLimitedDataProtector CreateProtector(string purpose);

          byte[] Protect(byte[] plaintext, DateTimeOffset expiration);

          byte[] Unprotect(byte[] protectedData, out DateTimeOffset expiration);
          }
          }

          DateTimeOffset 類型參數(shù)表示有效期

          以下示例展示了 ITimeLimitedDataProtector 的使用方法

          var protector = DataProtectionProvider.CreateProtector("testing").ToTimeLimitedDataProtector();
          var content = protector.Protect("Hello", DateTimeOffset.Now.AddMinutes(10));
          // 等待一段時(shí)間
          try
          {
          var rawContent = protector.Unprotect(content, out DateTimeOffset expiration);
          }
          catch (CryptographicException ex)
          {
          Logger.logError(ex.Message, ex);
          }

          Microsoft.AspNetCore.DataProtection 包中還提供了 EphemeralDataProtectionProvider 類,作為 IDataProtectionProvider 接口的一個(gè)實(shí)現(xiàn),它的加密和解密功能具有“一次性”的特點(diǎn),當(dāng)密文不需要持久化時(shí),可以使用這種方式

          private void EphemeralDataProtectionTest()
          {
          const string Purpose = "DemoPurpose";

          EphemeralDataProtectionProvider provider = new EphemeralDataProtectionProvider();
          var protector = provider.CreateProtector(Purpose);
          var content = protector.Protect("Hello");
          var rawContent = protector.Unprotect(content);

          EphemeralDataProtectionProvider provider2 = new EphemeralDataProtectionProvider();
          var protector2 = provider2.CreateProtector(Purpose);
          rawContent = protector2.Unprotect(content);// 這里會(huì)出現(xiàn)異常
          }

          對(duì)于第二個(gè) EphemeralDataProtectionProvider 盡管創(chuàng)建了 IDataProtector 時(shí),使用了相同的字符串,但由于是不同的實(shí)例,因此嘗試解密第一個(gè)對(duì)象加密的內(nèi)容時(shí),將會(huì)出錯(cuò),拋出 CryptographicException 異常

          相關(guān)文章

          《ASP.NET Core 與 RESTful API 開(kāi)發(fā)實(shí)戰(zhàn)》-- (第8章)-- 讀書(shū)筆記(中)


          《ASP.NET Core 與 RESTful API 開(kāi)發(fā)實(shí)戰(zhàn)》-- (第8章)-- 讀書(shū)筆記(上)


          《ASP.NET Core 與 RESTful API 開(kāi)發(fā)實(shí)戰(zhàn)》-- (第7章)-- 讀書(shū)筆記(下)


          《ASP.NET Core 與 RESTful API 開(kāi)發(fā)實(shí)戰(zhàn)》-- (第7章)-- 讀書(shū)筆記(中)


          《ASP.NET Core 與 RESTful API 開(kāi)發(fā)實(shí)戰(zhàn)》-- (第7章)-- 讀書(shū)筆記(上)


          《ASP.NET Core 與 RESTful API 開(kāi)發(fā)實(shí)戰(zhàn)》-- (第6章)-- 讀書(shū)筆記(下)


          《ASP.ENT Core 與 RESTful API 開(kāi)發(fā)實(shí)戰(zhàn)》-- (第6章)-- 讀書(shū)筆記(上)


          《ASP.ENT Core 與 RESTful API 開(kāi)發(fā)實(shí)戰(zhàn)》-- (第5章)-- 讀書(shū)筆記(下)


          《ASP.ENT Core 與 RESTful API 開(kāi)發(fā)實(shí)戰(zhàn)》-- (第5章)-- 讀書(shū)筆記(中)


          《ASP.ENT Core 與 RESTful API 開(kāi)發(fā)實(shí)戰(zhàn)》-- (第5章)-- 讀書(shū)筆記(上)


          《ASP.ENT Core 與 RESTful API 開(kāi)發(fā)實(shí)戰(zhàn)》-- (第4章)-- 讀書(shū)筆記(下)


          《ASP.ENT Core 與 RESTful API 開(kāi)發(fā)實(shí)戰(zhàn)》-- (第4章)-- 讀書(shū)筆記(上)


          《ASP.ENT Core 與 RESTful API 開(kāi)發(fā)實(shí)戰(zhàn)》(第3章)-- 讀書(shū)筆記(下)


          《ASP.ENT Core 與 RESTful API 開(kāi)發(fā)實(shí)戰(zhàn)》(第3章)-- 讀書(shū)筆記(中)


          《ASP.ENT Core 與 RESTful API 開(kāi)發(fā)實(shí)戰(zhàn)》(第3章)-- 讀書(shū)筆記(上)


          《ASP.ENT Core 與 RESTful API 開(kāi)發(fā)實(shí)戰(zhàn)》-- 讀書(shū)筆記(第2章)


          《ASP.ENT Core 與 RESTful API 開(kāi)發(fā)實(shí)戰(zhàn)》-- 讀書(shū)筆記(第1章)



          歡迎各位讀者加入微信群一起學(xué)習(xí)交流,
          在公眾號(hào)后臺(tái)回復(fù)“加群”即可~~


          瀏覽 88
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  你懂的 91| 69久久成人精品 | 欧美成人生活片一区三区 | 成人五月天在线导航 | 免费成人毛片 |