.NET MVC5 默認的用戶登陸組件是AspNet.Identity ,支持owin,而且微軟本身實現的一套owin 中間件叫 katanahtml
補充一下 katana項目源碼地址:https://katanaproject.codeplex.com/windows
如何用owin作用戶登陸 受權等這裏就不詳細說了,你們能夠自行搜索。api
登陸就有用戶狀態,用戶狀態通常就是保存在cookie 裏,cookie裏確定是保存的加密串了。cookie
那麼這個katana是如何解密跟加密呢?app
翻了大半天源碼,終於找到核心的2個類 CookieAuthenticationMiddleware,CookieAuthenticationHandlerasync
引用一下這篇比較全的文章,ide
做者最後說下回分解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 這個東西,底層實現我沒細看,有心的讀者能夠去研究一下,記得把成果分享給我喲)。