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

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

这个原始函数有超过200行代码,这里我省略了较多,但保留了关键、核心部分,想查阅原始代码可以移步Github链接:https://github.com/aspnet/AspNetKatana/blob/0fc4611e8b04b73f4e6bd68263e3f90e1adfa447/src/Microsoft.Owin.Security.Cookies/CookieAuthenticationHandler.cs#L130-L313

这里挑几点最重要的讲。

与MVC建立关系

建立关系的核心代码就是第一行,它从上文中提到的位置取回了AuthenticationResponseGrant,该Grant保存了Claims、AuthenticationTicket等Cookie重要组成部分:

AuthenticationResponseGrant signin = Helper.LookupSignIn(Options.AuthenticationType);
继续查阅LookupSignIn源代码,可看到,它就是从上文中的AuthenticationManager中取回了AuthenticationResponseGrant(有删减):

public AuthenticationResponseGrant LookupSignIn(string authenticationType)
{
 // ...
 AuthenticationResponseGrant grant = _context.Authentication.AuthenticationResponseGrant;
 // ...

 foreach (var claimsIdentity in grant.Principal.Identities)
 {
 if (string.Equals(authenticationType, claimsIdentity.AuthenticationType, StringComparison.Ordinal))
 {
  return new AuthenticationResponseGrant(claimsIdentity, grant.Properties ?? new AuthenticationProperties());
 }
 }

 return null;
}

如此一来,柳暗花明又一村,所有的线索就立即又明朗了。

Cookie的生成

从AuthenticationTicket变成Cookie字节串,最关键的一步在这里:

string cookieValue = Options.TicketDataFormat.Protect(model);
在接下来的代码中,只提到使用CookieManager将该Cookie字节串添加到Http响应中,翻阅CookieManager可以看到如下代码:

public void AppendResponseCookie(IOwinContext context, string key, string value, CookieOptions options)
{
 if (context == null)
 {
 throw new ArgumentNullException("context");
 }
 if (options == null)
 {
 throw new ArgumentNullException("options");
 }

 IHeaderDictionary responseHeaders = context.Response.Headers;
 // 省去“1万”行计算chunk和处理细节的流程
 responseHeaders.AppendValues(Constants.Headers.SetCookie, chunks);
}

有兴趣的朋友可以访问Github看原始版本的代码:https://github.com/aspnet/AspNetKatana/blob/0fc4611e8b04b73f4e6bd68263e3f90e1adfa447/src/Microsoft.Owin/Infrastructure/ChunkingCookieManager.cs#L125-L215

可见这个实现比较……简单,就是往Response.Headers中加了个头,重点只要看TicketDataFormat.Protect方法即可。

逐渐明朗

该方法源代码如下:

public string Protect(TData data)
{
 byte[] userData = _serializer.Serialize(data);
 byte[] protectedData = _protector.Protect(userData);
 string protectedText = _encoder.Encode(protectedData);
 return protectedText;
}

可见它依赖于_serializer、_protector、_encoder三个类,其中,_serializer的关键代码如下: