owin 中间件 katana 如何解密cookie

.NET MVC5 默认的用户登陆组件是AspNet.Identity ,支持owin,而且微软本身实现的一套owin 中间件叫 katanahtml

补充一下 katana项目源码地址:https://katanaproject.codeplex.com/windows

如何用owin作用户登陆 受权等这里就不详细说了,你们能够自行搜索。api

登陆就有用户状态,用户状态通常就是保存在cookie 里,cookie里确定是保存的加密串了。cookie

那么这个katana是如何解密跟加密呢?app

翻了大半天源码,终于找到核心的2个类 CookieAuthenticationMiddleware,CookieAuthenticationHandlerasync

引用一下这篇比较全的文章,ide

http://www.cnblogs.com/jesse2013/p/aspnet-identity-claims-based-authentication-and-owin.html?utm_source=tuicool&utm_medium=referralui

做者最后说下回分解CookieAuthenticationMiddleware这个东西,一直没等到下回,只能本身动手丰衣足食了。加密

CookieAuthenticationHandler 里面有2个方法spa

1,AuthenticateCoreAsync

2,ApplyResponseGrantAsync

前者是解密,后者是加密

咱们直接看解密的

  protected override async Task<AuthenticationTicket> AuthenticateCoreAsync()
        {
            AuthenticationTicket ticket = null;
            try
            {
                string cookie = Options.CookieManager.GetRequestCookie(Context, Options.CookieName);
                if (string.IsNullOrWhiteSpace(cookie))
                {
                    return null;
                }

                ticket = Options.TicketDataFormat.Unprotect(cookie);
       //这里省略 …………

 Unprotect(cookie); 这个方法就是解密的核心方法了

查找引用 找到SecureDataFormat<TData> 这个类

 

 public TData Unprotect(string protectedText)
        {
            try
            {
                if (protectedText == null)
                {
                    return default(TData);
                }

                byte[] protectedData = _encoder.Decode(protectedText);
                if (protectedData == null)
                {
                    return default(TData);
                }

                byte[] userData = _protector.Unprotect(protectedData);
                if (userData == null)
                {
                    return default(TData);
                }

                TData model = _serializer.Deserialize(userData);
                return model;
            }
            catch
            {
                // TODO trace exception, but do not leak other information
                return default(TData);
            }
        }

这里咱们能够看到,解密步骤分红了三个步骤

Decode(解码)
Unprotect(解除保护)
Deserialize(反序列化)

分别查看源码后发现
解码用的是 Base64 解保护用的windowsapi 里的CryptoAPI ,序列化用的是二进制序列化。

到这里我就停了,须要的知识已经搞清楚了。

那么我在项目里怎么解密呢?

我没有直接用CookieAuthenticationMiddleware这个类,这个依赖较多,也多是我没全看懂,反正没直接用。
既然知道三个步骤是什么了,干脆我也是3个步骤了。
Decode(解码)用Base64UrlTextEncoder
Deserialize用TicketSerializer
这两个类都是public 的,而且直接new 就能用的。katana源码里也是用这两个类。
麻烦的地方在
Unprotect

须要在Startup里面经过IAppBuilder 来建立 IDataProtector
不要问startup是什么,会用owin的都知道。
   public partial class Startup
    {
        public static IDataProtector dataProtector=null;
        private ILog loger = LogManager.GetLogger(typeof (Startup));
        public const string LoginCookieName = "xxx";
    
        public void ConfigureAuth(IAppBuilder app)
        {
           
             var op = new CookieAuthenticationOptions
            {
                AuthenticationType = LoginCookieName,
                LoginPath = new PathString("/Login")
                    //,ExpireTimeSpan = TimeSpan.FromHours(1)
                ,
                ExpireTimeSpan = TimeSpan.FromDays(30)
                ,
                SlidingExpiration = true

            };         
            app.UseCookieAuthentication(op);
           app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
     
              dataProtector = app.CreateDataProtector(
                      typeof(CookieAuthenticationMiddleware).FullName,
                      op.AuthenticationType, "v1");

        }
    }

用了一个静态变量来装

dataProtector 

(直觉用静态变量不太好,有其余方案请不吝赐教啊)

那么真正实现解密cookie的地方就在某个Controller里
   public async Task<ActionResult> DeCodeUser(string cookie)
        {
          
            byte[] protectedData = new Base64UrlTextEncoder().Decode(cookie);

            byte[] data = Startup.dataProtector.Unprotect(protectedData);
            var tick = new TicketSerializer().Deserialize(data);
            string userid = tick.Identity.GetUserId();
            AppUser currentUser = await UserManager.FindByIdAsync(userid);
            return Json(currentUser);
        }

只要传入这个须要解密的cookie就能获取用户信息出来了。

固然这个主要是用来探讨怎么解密 cookie而已,真正你要获取用户信息,直接调用 controller 里User就能够了。

有人会担忧,若是知道了解密方式,那岂不是只要cookie信息被截获 别人就能解出里面的信息?

固然不行,我写的这个例子是由于加密 跟解密的方法都在同一台机器上运行,因此所建立的

IDataProtector  其实包含着相同的密钥,相同的appname ,因此才可以加密解密对称。若是分开2台不一样的机器就
应该不行了(这个不太肯定,若是知道了appname等信息不知道能不能模仿,可是还有winapi CryptoAPI 这个东西,底层实现我没细看,有心的读者能够去研究一下,记得把成果分享给我哟)。
相关文章
相关标签/搜索