亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

坎坷路:ASP.NET5Identity身份驗證(上集)

2019-11-14 14:21:59
字體:
來源:轉載
供稿:網友

之所以為上集,是因為我并沒有解決這個問題,寫這篇博文的目的是紀錄一下我所遇到的問題,以免自己忘記,其實已經忘了差不多了,寫的過程也是自己回顧的過程,并且之前收集有關 asp.net 5 身份驗證的書簽已經太多了,所以必須記錄下來。

在前年(2014-12-10),我寫了這篇博文《愛與恨的抉擇:ASP.NET 5+EntityFramework 7》,背景是我當時打算用 ASP.NET 5 重寫一個 Web 項目,因為那時候 ASP.NET 5 剛發布不久(之前叫 vNext),所以當時抱了很大的激情投入在上面,但最后的結果是給自己澆了一盆冷水,放棄的原因文章中已經總結了,關于為啥放棄 ASP.NET 5,就是因為身份驗證的問題,現在時間過去一年多了,現在回過頭來看,其實還是蠻有意思的,比如下面我說一個。

其實最后我想要的功能是不綁定 DbContext,在 ASP.NET 5 項目中,只進行判斷操作,身份驗證在另外服務中進行,然后在本項目中可以實現類似 FormsAuthentication.SetAuthCookie 操作就可以了,但最后做了幾個 Demo 都不能實現,規定的一天時間,已經用完了,所以。。。

上面我前年想要實現的想法,其實我現在也在做這個工作,但中間已經過去一年多時間了,最后還是沒有實現。

登錄系統是一個獨立的站點,這是一個老的項目,身份驗證使用的是 Forms Authentication,因為涉及到其它站點,所以不能把登錄系統的身份驗證改寫為 Claims-based 或者 OAuth,這就意味著你需要讓其它站點的身份驗證方式,來兼容 Forms Authentication,登錄系統獨立的好處是,其它站點不需要管理用戶的登錄和注銷功能,只需要判斷用戶有沒有通過身份驗證即可,就像我當時說的一樣,我只需要進行判斷操作,但最后做了很多 Demo 研究,還是實現不了,現在回過頭來看,當時如果實現了才真是見鬼了,因為 ASP.NET 5 根本就不支持 Forms Authentication(后面詳細說),所以,懂得放棄也是好事,畢竟時間是寶貴的。

后來,那個 Web 項目放棄使用 ASP.NET 5 + EF 7,然后用 ASP.NET MVC 5 + EF 6 重寫完成了,但心里面還是很不甘心,其實在當時我并不是很懂 ASP.NET Identity 身份驗證,所以也導致浪費了很多時間,后來花了點時間重新學習了 ASP.NET Identity,也就是記錄的這篇博文《跌倒了,再爬起來:ASP.NET 5 Identity》,這篇博文的主要內容是查看 ASP.NET 5 Identity 的源碼,然后拋棄 applicationDbContext、UserManager、SignInManager 等等,直接實現用戶的登錄操作,并且成功實現驗證,看到博文最后,你會發現 ASP.NET Identity 和之前的 Forms Authentication 還是有很多不同的,但都是基于 Cookie 加密的方式,下面看三段代碼:

Forms Authentication 方式登錄:

System.Web.Security.FormsAuthentication.SetAuthCookie("xishuai", false);

ASP.NET Identity 方式登錄(截止 2015-01-11):

var userId = await UserManager.GetUserIdAsync(user, cancellationToken);Context.Response.SignIn(StoreTwoFactorInfo(userId, loginPRovider));

ASP.NET Identity 方式登錄(最新,來自 SignInManager.cs):

var userId = await UserManager.GetUserIdAsync(user);await Context.Authentication.SignInAsync(Options.Cookies.TwoFactorUserIdCookieAuthenticationScheme, StoreTwoFactorInfo(userId, loginProvider));

首先,ASP.NET Identity 和 Forms Authentication 都是通過把用戶信息加密后,放入響應頭的 Cookie 中,只不過兩種 Cookie 加密的方式不同(ASP.NET Identity 會更加復雜),所以如果登錄方式使用的 Forms Authentication,那在 ASP.NET 5 中就沒有辦法判斷用戶驗證,因為加密和解密要一一對應,如果不對應,那獲取到的 Cookie 就沒有辦法解密成功,所以也就沒有辦法通過身份驗證(IsAuthenticated 為 false),另外,關于 ASP.NET Identity,它不像一個技術點,有點類似于框架的概念,只不過把身份驗證的內容包裝了一下,比如產生了 ApplicationDbContext、UserManager、SignInManager 等等,作用就是讓你使用更加方便,查看源碼就知道,其實核心內容就是上面那些。

關于 SignInManager.cs 中的代碼,我們發現有很大的變化,比如 SignInAsync 中的代碼,Context.Authentication.SignInAsync 的實現,我們可以從 Security 項目中找到,具體在 Microsoft.AspNet.Authentication/AuthenticationHandler.cs,感覺和之前的相比變的復雜了。

回到最初的問題:在 ASP.NET 5 中,如何實現身份驗證(兼容 Forms Authentication)?

上面的問題雖然看起來很簡單,但是有個首要前提:ASP.NET 5 不支持 Forms Authentication,那么這個問題就變得復雜了,但我們可以拆分下:

  1. 了解現階段 ASP.NET 5 身份驗證的實現方式。
  2. 在 ASP.NET 5 中,解密 Cookie(通過 Forms Authentication 加密)。

我們先研究第一問題,首先,我們不使用 ASP.NET 5 Identity,而是直接登錄進行身份驗證,為什么要這么做?因為登錄系統不能重寫,所以我們使用 ASP.NET 5 Identity 也沒有什么意義,況且多了一大堆不必要的東西(UserManager、SignInManager 等),會讓問題變的復雜,在之前的博文最后,有一個簡單示例,如下:

//app.UseIdentity();app.UseCookieAuthentication((cookieOptions) =>{    cookieOptions.AuthenticationType = IdentityOptions.ApplicationCookieAuthenticationType;    cookieOptions.AuthenticationMode = AuthenticationMode.Active;    cookieOptions.CookieHttpOnly = true;    cookieOptions.CookieName = ".CookieName";    cookieOptions.LoginPath = new PathString("/Account/Login");    cookieOptions.CookieDomain = ".mysite.com";}, "AccountAuthorize");[AllowAnonymous]public IActionResult Login(string returnUrl = null){    var userId = "xishuai";    var identity = new ClaimsIdentity(IdentityOptions.ApplicationCookieAuthenticationType);    identity.AddClaim(new Claim(ClaimTypes.Name, userId));    Response.SignIn(identity);    return Redirect(returnUrl);}

上面是一年前的代碼,一年后變成了這樣:

//app.UseIdentity();app.UseCookieAuthentication((cookieOptions) =>{    cookieOptions.AutomaticAuthenticate = true;    cookieOptions.AutomaticChallenge = true;    cookieOptions.CookieHttpOnly = true;    cookieOptions.ExpireTimeSpan = TimeSpan.FromMinutes(43200);    cookieOptions.LoginPath = new PathString("/account/login");    cookieOptions.CookieName = ".CNBlogsCookie";    cookieOptions.CookiePath = "/";});public async Task<IActionResult> Login(string returnUrl = null){    var userId = "xishuai";    var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);    identity.AddClaim(new Claim(ClaimTypes.Name, userId));    await HttpContext.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(identity), new AuthenticationProperties() { IsPersistent = true });    return Redirect(returnUrl);}

上面看似沒問題的代碼,但實際使用中遇到了很多的問題,比如生成 Cookie 的 Expires 為 session,也就是我們設置的 ExpireTimeSpan 沒有作用,解決方式:SignInAsync 需要傳遞一個 new AuthenticationProperties() { IsPersistent = true } 參數,另外還有其它問題,我現在已經記不得了,不過記錄了一個 Issue:HttpContext.Authentication.SignInAsync not working,再貼一下 project.json 中程序包版本,后來測試很多次,可能是版本不一致引起的:

"dependencies": {  "Microsoft.AspNet.Authentication.Cookies": "1.0.0-rc2-16160",  "Microsoft.AspNet.DataProtection.Extensions": "1.0.0-rc2-15874",  "Microsoft.AspNet.Diagnostics": "1.0.0-rc2-16303",  "Microsoft.AspNet.IISPlatformHandler": "1.0.0-rc2-15994",  "Microsoft.AspNet.Mvc": "6.0.0-rc2-16614",  "Microsoft.AspNet.Mvc.TagHelpers": "6.0.0-rc2-16614",  "Microsoft.AspNet.Server.Kestrel": "1.0.0-rc2-16156",  "Microsoft.AspNet.StaticFiles": "1.0.0-rc2-16036",  "Microsoft.AspNet.Tooling.Razor": "1.0.0-rc2-15994",  "Microsoft.Extensions.Configuration.FileProviderExtensions": "1.0.0-rc2-15905",  "Microsoft.Extensions.Configuration.Json": "1.0.0-rc2-15905",  "Microsoft.Extensions.Logging": "1.0.0-rc2-15907",  "Microsoft.Extensions.Logging.Console": "1.0.0-rc2-15907",  "Microsoft.Extensions.Logging.Debug": "1.0.0-rc2-15907",  "Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0-rc2-16142"}

后來折騰了很久,測試可以使用了,但發布到服務器的時候,又出現了問題,因為站點使用的是負載均衡,需要把程序發布到兩臺服務器上,當兩臺服務器同時在跑的時候,比如登錄請求到一臺服務器,驗證剛好請求到另一臺服務器,這時候身份驗證就沒有效果,然后跳轉到登錄頁面,這個問題折騰我很久,自己怎么配置都不行,后來沒有辦法,向微軟提了一個 Issue:Multiple web servers CookieAuthentication does not work,問題提出后,很快有人回復了,問題原因是需要提供一個 key,這個有點像 Forms Authentication 方式中 Web.config 的 MachineKey,我們需要將身份驗證的配置,修改如下:

var dataProtection = new Microsoft.AspNet.DataProtection.DataProtectionProvider(new DirectoryInfo(@"c:/shared-auth-ticket-keys/"));app.UseCookieAuthentication((cookieOptions) =>{    cookieOptions.AutomaticAuthenticate = true;    cookieOptions.AutomaticChallenge = true;    cookieOptions.CookieHttpOnly = true;    cookieOptions.ExpireTimeSpan = TimeSpan.FromMinutes(43200);    cookieOptions.LoginPath = new PathString("/account/login");    cookieOptions.CookieName = ".CNBlogsCookie";    cookieOptions.CookiePath = "/";    cookieOptions.DataProtectionProvider = dataProtection;});

后來重新發布,測試還是出現問題,和之前的問題一樣,跳轉到登錄頁面,然后我嘗試把一臺服務器生成在 c:/shared-auth-ticket-keys 目錄下的 key 文件,拷貝到另外一臺服務器中,但還是沒用,過了很多天,有人回復了:

You need to point the key directory to a shared directory which both applications can access. Putting it in c:/shared-auth-ticket-keys/ isn't enough in multiple server scenarios, as it's still going to create a key ring local to each machine.
You need to create an UNC share somewhere that both applications can access, and use that, for example /keystore/keystore
Or you implement a key store yourself suitable to your architecture, for example, using SQL Server.

大致意思是,雖然是同一個目錄,但會在不同服務器生成不同的 key 文件,所以身份驗證就不通過,解決方式是使用 key 共享文件,這樣讓不同服務器都能訪問同一個 key 文件,另外一種方式是將 key 存儲在一個地方,比如 SQL Server 中,但我不是很了解 key 的讀取和存儲方式,所以,我最后嘗試用第一種方式解決,只需要我們將目錄更改為共享目錄:

var dataProtection = new Microsoft.AspNet.DataProtection.DataProtectionProvider(new DirectoryInfo(@"//10.10.10.10/shared-auth-ticket-keys/"));

后來再重新發布,還是出現了問題,比如共享文件放在一臺服務器上,這臺服務器訪問沒用什么問題,但另一臺服務器卻不能訪問,文件資源管理器可以訪問此共享文件,這個問題也折騰我很久,但不和 ASP.NET 5 相關,主要問題是不了解 ASP.NET 如何訪問共享文件,后來找資料解決了,記錄了一篇博文:ASP.NET 訪問共享文件夾。

目前的情況:第一個問題已經實現,但是比較簡陋,開始考慮并實現第二個問題。

一開始的時候,我提了一個 Issue:Share ASP.NET MVC 5 Forms authentication?

這個 Issue 我覺得很有價值,它讓我了解了很多東西,比如 ASP.NET 5 不支持 Forms Authentication,ASP.NET 5 和 Forms Authentication 的 Cookie 加密方式不同,ASP.NET 5 會更加復雜,因為登錄系統不能被重寫,并且 ASP.NET 5 不支持 Forms Authentication,那么擺在我面前的只有一條路,在 ASP.NET 5 中,解密 Cookie(通過 Forms Authentication 加密),針對這個問題,我的一些想法:

其實看起來這個問題好像不是很復雜,通過 Key 加密生成 Cookie(Forms Authentication),然后通過下面方式獲取 Cookie(ASP.NET 5):

var cookies = Request.Cookies.First(x => x.Key == ".CNBlogsCookie").Value;

然后通過某些手段解密生成 IdentityUser 對象,對,沒錯,就這么簡單。

我們先不住 ASP.NET 5 中實現下,很簡單:

var cookies = "";FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(cookies);string[] roles = authTicket.UserData.Split(new char[] { ';' });var user = new GenericPrincipal(User.Identity, roles);

這段代碼是執行成功的,但我們需要在 Web.config 中,配置如下代碼:

這段代碼必須要和登錄站點中的配置一樣,原因是加密和解密的方式要一一對應,接下來的工作,我們需要在 ASP.NET 5 中實現上面的代碼,但你會發現找不到 FormsAuthentication.Decrypt 了,這么辦呢?只能查看源碼,然后把相關代碼貼出來編譯一下,如果成功了(我嘗試了很多次,因為涉及的代碼太多,實現起來非常困難),這是第一步,第二步我們將編譯通過的代碼,放在 ASP.NET 5 中再編譯一次,這個工作我還沒做,不過看起來并不是那么簡單,因為運行時和基礎類庫都發生變化了。

如果重寫這部分代碼,我貼一下需要的一些資源(后面再嘗試下):

  • System.Web/Security/FormsAuthentication.cs(referencesource)
  • System.Web/Security/FormsAuthentication.cs(GitHub)
  • System.Web/Security/FormsAuthentication.cs(mono)
  • https://github.com/aspnet/Identity
  • https://github.com/aspnet/Security
  • https://github.com/aspnet/dataprotection

后來,上面那個 Issue 有人回復如下:

看到這,有點想哭的趕腳,但不管怎樣,還是要嘗試下,希望下集是一個成功的博文記錄,未完待續。。。

最后,貼一下這段時間累積的有關資料:

  • Sharing cookies between applications.
  • Understanding OWIN Forms authentication in MVC 5
  • asp.net - Cookie-based Forms Authentication Across MVC 5 and MVC 6 (vNext) Applications
  • MVC5 - ASP.NET Identity登錄原理 - Claims-based認證和OWIN
  • FormsAuthenticationTicket基于forms的驗證
  • asp.net Forms表單驗證 使用經驗及驗證流程分析
  • Difference between Claims vs OAuth
  • Adding ASP.NET Identity to an Empty or Existing Web Forms Project
  • authentication - CookieAuthenticationOptions, ExpireTimeSpan does not work
  • Understanding OWIN Forms authentication in MVC 5
  • Reading Katana Cookie Authentication Middleware’s Cookie from FormsAuthenticationModule
  • MVC Forms Authentication and Storing Data in the Cookie
  • Use MachineKey in ASP.NET vNext
  • Setting the Machine Key as usual? ... or any other gotchas for web farm scenarios?
  • Key Encryption At Rest

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
成人免费在线视频网站| 亚洲国产一区自拍| 国产精品黄色av| 欧美精品videos另类日本| 亚洲免费视频一区二区| 色999日韩欧美国产| 国产一区二区三区在线观看网站| 久久久亚洲天堂| 国产成人精品久久| 国产精品久久久久久久久久小说| 国产日韩综合一区二区性色av| 亚洲国产99精品国自产| 中文在线资源观看视频网站免费不卡| 国产午夜精品全部视频播放| 久久久噜噜噜久久| 久久躁狠狠躁夜夜爽| 欧美在线观看日本一区| 日韩小视频在线观看| 亚洲美女激情视频| 国产999精品视频| 欧美一区二区三区图| 久久亚洲综合国产精品99麻豆精品福利| 亚洲精品国产拍免费91在线| 亚洲性夜色噜噜噜7777| 午夜精品一区二区三区在线视| 国产精品久久久久久久久免费看| 日韩高清电影免费观看完整| 亚洲免费av电影| 2019日本中文字幕| 欧美理论在线观看| 最近中文字幕mv在线一区二区三区四区| 91极品视频在线| 成人免费观看49www在线观看| 日韩精品高清在线| 国产999精品| 91精品久久久久久久久中文字幕| 亚洲free嫩bbb| 国内精品小视频| 久久福利视频网| 久久久久久久一区二区| 久久人人爽人人爽人人片亚洲| 欧洲美女免费图片一区| 日韩高清欧美高清| 7777精品久久久久久| 欧美电影在线观看高清| 久久香蕉频线观| 久久99久久99精品中文字幕| 青青草99啪国产免费| 亚洲国产另类 国产精品国产免费| 亚洲精品国偷自产在线99热| 国内精品视频一区| 欧美成年人视频网站| 国产成人av在线播放| 成人高清视频观看www| 最近中文字幕2019免费| 久久久久久综合网天天| 久久久国产精品视频| 91老司机在线| 久久久久亚洲精品国产| 国产91在线高潮白浆在线观看| 欧美综合第一页| 久久视频免费在线播放| 97国产精品免费视频| 欧美日韩中文字幕在线| 国产日韩欧美视频在线| 日韩精品在线视频| 国产男人精品视频| 日韩av中文字幕在线| 国产精品久久久久av| 日本高清不卡在线| 91久久久久久久久久久| 久久精品青青大伊人av| 久久久人成影片一区二区三区观看| 国模精品一区二区三区色天香| 色琪琪综合男人的天堂aⅴ视频| 欧美老少配视频| 91九色综合久久| 欧美激情综合色综合啪啪五月| 亚洲伊人久久综合| 欧美成人四级hd版| 日韩av电影在线网| 8050国产精品久久久久久| 91在线观看免费观看| 国产丝袜精品视频| 国产激情久久久| 亚洲精品一区二区三区不| 亚洲国产欧美自拍| 日韩中文字幕精品视频| 国产偷亚洲偷欧美偷精品| 亚洲999一在线观看www| 国产日韩欧美黄色| 成人激情免费在线| 69av成年福利视频| 成人天堂噜噜噜| 国产日韩欧美日韩大片| 精品久久久久久国产91| 亚洲精品永久免费精品| 欧美精品一区二区三区国产精品| 国产精品久久av| 亚洲精品免费一区二区三区| 久久久久国产精品一区| 欧美精品做受xxx性少妇| 91精品国产91久久久| 欧美国产日韩二区| 亚洲一区中文字幕在线观看| 91在线免费视频| 色先锋久久影院av| 国产精品久久久久免费a∨大胸| 欧美www在线| 国产一区二区三区视频| 亚洲高清福利视频| 欧美猛男性生活免费| 国产精品偷伦一区二区| 亚洲aa在线观看| 激情成人在线视频| 狠狠躁夜夜躁人人爽天天天天97| 久久91亚洲精品中文字幕奶水| 亚洲a在线观看| 中文字幕v亚洲ⅴv天堂| 国产精品99一区| 精品国产一区二区三区久久狼5月| 亚洲精选一区二区| 午夜剧场成人观在线视频免费观看| 欧美激情亚洲综合一区| 日韩精品www| 欧美怡红院视频一区二区三区| 亚洲精品视频免费| 亚洲在线第一页| 久久久久久一区二区三区| 国产精品久久久久久久久免费看| 日韩欧美国产中文字幕| 欧美老肥婆性猛交视频| 日本欧美一二三区| 亚洲福利视频二区| 国产一区二区三区日韩欧美| 黑人极品videos精品欧美裸| 久久天天躁夜夜躁狠狠躁2022| 久青草国产97香蕉在线视频| 日韩久久精品电影| 91精品国产成人| 国产精品十八以下禁看| 操人视频在线观看欧美| 国产性色av一区二区| 91沈先生作品| 国产精品a久久久久久| 亚洲第一精品夜夜躁人人躁| 欧美日韩视频免费播放| 成人免费看黄网站| 91视频国产一区| 色樱桃影院亚洲精品影院| 91精品国产91| 亚洲石原莉奈一区二区在线观看| 国产精品久久久久久久久粉嫩av| 亚洲色图在线观看| 欧美日韩国产一区中文午夜| 欧美日韩中文字幕在线视频| 久久久国产精品视频| 热久久这里只有精品| 日韩av在线资源| 亚洲激情 国产| 久久久国产一区二区| 免费91麻豆精品国产自产在线观看| 日本中文字幕不卡免费| 日韩精品在线第一页|