ASP.NET Cookie是怎么生成的(推荐)

2020-02-01 09:26:42丽君

public virtual byte[] Serialize(AuthenticationTicket model)
{
 using (var memory = new MemoryStream())
 {
 using (var compression = new GZipStream(memory, CompressionLevel.Optimal))
 {
  using (var writer = new BinaryWriter(compression))
  {
  Write(writer, model);
  }
 }
 return memory.ToArray();
 }
}

其本质是进行了一次二进制序列化,并紧接着进行了gzip压缩,确保Cookie大小不要失去控制(因为.NET的二进制序列化结果较大,并且微软喜欢搞xml,更大😂)。

然后来看一下_encoder源代码:

public string Encode(byte[] data)
{
 if (data == null)
 {
 throw new ArgumentNullException("data");
 }

 return Convert.ToBase64String(data).TrimEnd('=').Replace('+', '-').Replace('/', '_');
}

可见就是进行了一次简单的base64-url编码,注意该编码把=号删掉了,所以在base64-url解码时,需要补=号。

这两个都比较简单,稍复杂的是_protector,它的类型是IDataProtector。

IDataProtector

它在CookieAuthenticationMiddleware中进行了初始化,创建代码和参数如下:

IDataProtector dataProtector = app.CreateDataProtector(
 typeof(CookieAuthenticationMiddleware).FullName,
 Options.AuthenticationType, "v1");

注意它传了三个参数,第一个参数是CookieAuthenticationMiddleware的FullName,也就是"Microsoft.Owin.Security.Cookies.CookieAuthenticationMiddleware",第二个参数如果没定义,默认值是CookieAuthenticationDefaults.AuthenticationType,该值为定义为"Cookies"。

但是,在默认创建的ASP.NET MVC模板项目中,该值被重新定义为ASP.NET Identity的默认值,即"ApplicationCookie",需要注意。

然后来看看CreateDataProtector的源码:

public static IDataProtector CreateDataProtector(this IAppBuilder app, params string[] purposes)
{
 if (app == null)
 {
 throw new ArgumentNullException("app");
 }

 IDataProtectionProvider dataProtectionProvider = GetDataProtectionProvider(app);
 if (dataProtectionProvider == null)
 {
 dataProtectionProvider = FallbackDataProtectionProvider(app);
 }
 return dataProtectionProvider.Create(purposes);
}

public static IDataProtectionProvider GetDataProtectionProvider(this IAppBuilder app)
{
 if (app == null)
 {
 throw new ArgumentNullException("app");
 }
 object value;
 if (app.Properties.TryGetValue("security.DataProtectionProvider", out value))
 {
 var del = value as DataProtectionProviderDelegate;
 if (del != null)
 {
  return new CallDataProtectionProvider(del);
 }
 }
 return null;
}

可见它先从IAppBuilder的"security.DataProtectionProvider"属性中取一个IDataProtectionProvider,否则使用DpapiDataProtectionProvider。

我们翻阅代码,在OwinAppContext中可以看到,该值被指定为MachineKeyDataProtectionProvider:

builder.Properties[Constants.SecurityDataProtectionProvider] = new MachineKeyDataProtectionProvider().ToOwinFunction();