zoukankan      html  css  js  c++  java
  • owin 中间件 katana 如何解密cookie

    .NET MVC5 默认的用户登录组件是AspNet.Identity ,支持owin,并且微软自己实现的一套owin 中间件叫 katana

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

    如何用owin做用户登录 授权等这里就不详细说了,大家可以自行搜索。

    登录就有用户状态,用户状态一般就是保存在cookie 里,cookie里肯定是保存的加密串了。

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

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

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

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

    作者最后说下回分解CookieAuthenticationMiddleware这个东西,一直没等到下回,只能自己动手丰衣足食了。

    CookieAuthenticationHandler 里面有2个方法

    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 这个东西,底层实现我没细看,有心的读者可以去研究一下,记得把成果分享给我哟)。


     
  • 相关阅读:
    关于返回上一页功能
    Mybatis Update statement Date null
    SQLite reset password
    Bootstrap Validator使用特性,动态(Dynamic)添加的input的验证问题
    Eclipse使用Maven2的一次环境清理记录
    Server Tomcat v7.0 Server at localhost failed to start
    PowerShell一例
    Server Tomcat v7.0 Server at libra failed to start
    商标注册英语
    A glance for agile method
  • 原文地址:https://www.cnblogs.com/7rhythm/p/4905134.html
Copyright © 2011-2022 走看看