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

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

可见,最终所有的代码都是调用了AuthenticationManager.SignIn方法,所以该方法是创建Cookie的关键。

AuthenticationManager的实现定义在Microsoft.Owin中,因此无法在ASP.NET Identity中找到其源代码,因此我们打开Microsoft.Owin的源代码继续跟踪(有删减):

public void SignIn(AuthenticationProperties properties, params ClaimsIdentity[] identities)
{
 AuthenticationResponseRevoke priorRevoke = AuthenticationResponseRevoke;
 if (priorRevoke != null)
 {
 // ...省略不相关代码
 AuthenticationResponseRevoke = new AuthenticationResponseRevoke(filteredSignOuts);
 }

 AuthenticationResponseGrant priorGrant = AuthenticationResponseGrant;
 if (priorGrant == null)
 {
 AuthenticationResponseGrant = new AuthenticationResponseGrant(new ClaimsPrincipal(identities), properties);
 }
 else
 {
 // ...省略不相关代码

 AuthenticationResponseGrant = new AuthenticationResponseGrant(new ClaimsPrincipal(mergedIdentities), priorGrant.Properties);
 }
}

AuthenticationManager的Github链接如下:https://github.com/aspnet/AspNetKatana/blob/c33569969e79afd9fb4ec2d6bdff877e376821b2/src/Microsoft.Owin/Security/AuthenticationManager.cs

可见它用到了AuthenticationResponseGrant,继续跟踪可以看到它实际是一个属性:

public AuthenticationResponseGrant AuthenticationResponseGrant
{
 // 省略get
 set
 {
 if (value == null)
 {
  SignInEntry = null;
 }
 else
 {
  SignInEntry = Tuple.Create((IPrincipal)value.Principal, value.Properties.Dictionary);
 }
 }
}

发现它其实是设置了SignInEntry,继续追踪:

public Tuple<IPrincipal, IDictionary<string, string>> SignInEntry
{
 get { return _context.Get<Tuple<IPrincipal, IDictionary<string, string>>>(OwinConstants.Security.SignIn); }
 set { _context.Set(OwinConstants.Security.SignIn, value); }
}

其中,_context的类型为IOwinContext,OwinConstants.Security.SignIn的常量值为"security.SignIn"。

跟踪完毕……

啥?跟踪这么久,居然跟丢啦!?
当然没有!但接下来就需要一定的技巧了。

原来,ASP.NET是一种中间件(Middleware)模型,在这个例子中,它会先处理MVC中间件,该中间件处理流程到设置AuthenticationResponseGrant/SignInEntry为止。但接下来会继续执行CookieAuthentication中间件,该中间件的核心代码在aspnet/AspNetKatana仓库中可以看到,关键类是CookieAuthenticationHandler,核心代码如下:

protected override async Task ApplyResponseGrantAsync()
{
 AuthenticationResponseGrant signin = Helper.LookupSignIn(Options.AuthenticationType);
 // ... 省略部分代码

 if (shouldSignin)
 {
 var signInContext = new CookieResponseSignInContext(
  Context,
  Options,
  Options.AuthenticationType,
  signin.Identity,
  signin.Properties,
  cookieOptions);

 // ... 省略部分代码

 model = new AuthenticationTicket(signInContext.Identity, signInContext.Properties);
 // ... 省略部分代码

 string cookieValue = Options.TicketDataFormat.Protect(model);

 Options.CookieManager.AppendResponseCookie(
  Context,
  Options.CookieName,
  cookieValue,
  signInContext.CookieOptions);
 }
 // ... 又省略部分代码
}