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 這個東西,底層實現我沒細看,有心的讀者能夠去研究一下,記得把成果分享給我喲)。
相關文章
相關標籤/搜索