本來想直接就開始介紹Identity的部分,奈何自己挖坑太深,高舉高打的方法不行。只能自己默默下載了Katana的源代碼研究了好一段時間。發現要想能夠理解好用好Identity, Claims是一個繞不過的內容。今天就和大家一起分享一下什么是Claims以及為什么Identity要基於Claims.
閱讀目錄:
一. 什么是Claims以及基於Claims的identity驗證
二. 使用基於Claims的Identity驗證的優勢
三. Claims是如何應用在Asp.net中?
四,一些更深入的補充說明
一,什么是Claims以及基於Claims的identity驗證
實際上,基於Claims的identity驗證早已經被應用到我們生活中的很多方面。一個非常典型的例子就是我們到機場登機的過程。我們乘坐飛機,是不能夠直接直接拿着機票和身份證就上飛機的,需要先到櫃台上領登機牌. 到了指定櫃台上,出示身份證和機票,辦理物品托運,選好座位,確認后,才能換取登機牌。這個時候你才能憑借登機牌過安檢和上飛機。
登機過程中,工作人員掃一下這個小小的登機牌,就能獲取到很多信息: 比如,你已經是經過航空公司認證過的乘客,你的航班號,座位號,你的名字等。工作人員只要核對這些信息,就會允許你上對應的飛機和指定的座位。
以Claims的角度重新看待登機過程
OK. 我們再來捋一捋這個過程,用Claims的角度來重新描述和整理一下。
首先Claim就是一個描述. 這個例子中, 包含在登機牌上的一個一個信息,就是一個一個Claim. 這些Claims是這樣的:
乘客的名字叫Justrun
乘坐的航班是MF8858
座位號是34J
............................
所有上面的Claims就組成了Identity, 也就是登機牌。這個登機牌是基於Claims的。
這個登機牌是經過航空公司的工作人員驗證后,發給我的,那么發行者航空公司就是Issuer。
登機的時候,工作人員看到你的登機牌就會放行的原因是, 他信任這些Claims, 因為這些Claims的Issuer是trust的(航空公司)。比對完這些Claims,如果你登機的航班正確,就會讓你登機。
二,使用基於Claims的Identity驗證的優勢
看起來上面的過程好像非常麻煩,不是嗎? 為什么不就拿着身份證和機票直接登機,不是更加方便乘客嗎?
它的好處就是簡單的隔離了驗證(Authentication)和授權(authorization)兩個部分,但這也是它最大的優勢。
想想看,如果我們沒有了登機牌會是一個什么景象。工作人員要在飛機門口擺上設備,驗證你的機票和身份證信息,給你辦理行李托運,然后讓你選座位........ 簡直就不可想象。
有了登機牌, 驗證就由航公公司來做,航空公司負責驗證和發放登機牌,空姐就只需要查看你的登機牌,讓你登機並決定你有沒有權限座頭等艙。
有了Claims Identity, 那么創建Claims Identity就可以由多種多樣的驗證過程來做,比如可以通過用戶名密碼,Active Direcity, 第三方登錄(Google, Facebook,QQ,微博等),而我們的程序就主要根據Claims Identity來判斷用戶是否能夠使用我們的系統,以及決定用戶可以使用和不能使用系統中的那些功能。
這樣,驗證就完全和應用程序分開,開發應用程序的時候,只要我們使用的是基於Claims的Identity驗證,就不用擔心以后驗證方式的的擴展和修改。
三,Claims是如何應用在Asp.net中?
在Visual Studio 2013中,創建一個Asp.net MVC項目。這個默認的Asp.net MVC項目中,權限驗證默認使用的是CookieAuthentication。
app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new PathString("/Account/Login"), Provider = new CookieAuthenticationProvider { // Enables the application to validate the security stamp when the user logs in. // This is a security feature which is used when you change a password or add an external login to your account. OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>( validateInterval: TimeSpan.FromMinutes(30), regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager)) } });
啟動網站,能夠看到常規的登錄注冊流程。當我們要訪問受保護的頁面的時候,會轉到登錄頁面上。
現在我們在這個默認的MVC項目中做個小試驗,不通過注冊,登錄,直接寫入偽造的Claims信息來通過驗證。
首先,我們在ManageController上,添加一個ProtectedPage頁面,由於ManageController整個Controller都添加上了[Authorize],所以默認ProtectedPage是需要登錄之后才能訪問的。
public async Task<ActionResult> ProtectedPage() { return new ContentResult { Content = "This is a protected Page" }; }
直接敲入網址,http://localhost:4572/Manage/ProtectedPage , 和我們的預期一樣,直接轉到了登錄頁面。
接下來,是我們的重頭戲,我們將給自己偽造Claims, 騙過Authentication, 獲得訪問ProtectedPage的權限。
在HomeController上,創建一個AddClaim頁面,偽造Claims的過程如下:
public ActionResult AddClaim() { var claims = new List<Claim>//創建我們的Claim { new Claim(ClaimTypes.Name, "Peter"), new Claim(ClaimTypes.Email, "justrun_test@outlook.com") }; var identity = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);//構建ClaimsIdentity var ctx = Request.GetOwinContext(); var authenticationManager = ctx.Authentication;//通過OWIN Context獲取我們的Authentication Manager authenticationManager.SignIn(identity); return Content("Login Success"); }
訪問AddClaims頁面,看看效果。
我們的AddClaims起到效果了,通過人為的添加Claims信息,我們順利的得到了訪問ProtecedPage的權限。
四,一些更深入的補充說明
1. AuthenticationMiddleware如何判斷用戶是否是合法用戶的?
ClaimIdentity相當於是登機牌,也就是我們的系統的通行證。構建的ClaimIdentity,最后會通過加密的方式,轉換成加密字符,保存到Cookie中。Authentication中間層會通過檢查用戶Cookie中是否有ClaimIdentity,來判斷當前訪問的用戶是否是合法用戶。
2. 誰是Issuer?
在上面的例子中,Issuer就是我們自己,在AddClaims Action中,我們直接構造了CliamIdentity. 如果使用傳統的用戶名,密碼登陸的方式的話,當驗證通過,也是同樣構造ClaimIdentity, 只是上面的例子中,我們跳過了這步。
在Katana中,還有FacebookAuthenticationMiddleware, GoogleAuthenticationMiddleware等實現,它們是Issuer就分別是Facebook和Google. 以FacebookAuthenticationMiddleware為例子,當FacebookAuthenticationMiddleware檢查Cookie,發面沒有ClaimIdentity,就會轉到Facebook,要求提供Facebook賬號信息。當用戶登錄Facebook賬號,同意授權給我們的站點該用戶Facebook信息。這個時候FacebookAuthenticationMiddleware根據這些信息,構造CliamIdentity。
3. 補充閱讀:
想更多的了解OWIN以及Katana,可以看看下面這些文章
了解更多細節,可以直接down源碼:
Katana源碼: https://katanaproject.codeplex.com/SourceControl/latest#README
Asp.net Identity源碼: https://github.com/aspnet/Identity/tree/dev/src/Microsoft.AspNet.Identity