23

我有一個AngularJS客戶端應用程序使用javascript(而不是coffeescript或打字稿)Oauth2來驗證WebAPI 2應用程序使用最新的Identity 2。我應用程序中的所有軟件都是最新的,基於this example。我的客戶端瀏覽器目標是IE9及以上。如何在使用AngularJS,WebAPI 2和Oauth 2時將授權信息發回我的客戶端應用程序?

請注意,我對上面的示例做了一些小修改,因爲我沒有對使用轉換髮送到服務器的所有數據進行urlen編碼。相反,我用urlencode只是在下面的身份驗證方法:

user.authenticate = function (userName, password, rememberMe, successCallback, errorCallback) { 
    var config = { 
     method: 'POST', 
     url: '/Token', 
     headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, 
     data: 'grant_type=password&username=' + encodeURIComponent(userName) + '&password=' + encodeURIComponent(password), 
    }; 

我與VS2013更新2和服務器上開發,我使用C#,最新的實體框架和SQL Server 2012的

登錄我的客戶端向WebAPI調用/ Token方法並傳遞用戶標識和密碼。 WebAPI然後用一個令牌給我存儲的客戶端迴應。對於每個請求的WebAPI令牌被髮回,並驗證:

$http.defaults.headers.common.Authorization = 'Bearer ' + user.data.bearerToken; 

這個作品非常好,到目前爲止,但因爲它代表應用程序無法告訴分配有不同角色的用戶之間的差異。

某些WebAPI方法只能由具有特定角色的用戶執行。我想調整我的前端AngularJS應用程序的菜單,以便只有當用戶具有此角色時,纔會顯示相應的鏈接。我意識到這不會阻止用戶檢查HTML和發佈,但我不關心這一點,因爲我仍然會有方法修飾來限制用戶不在角色中執行操作的能力。

有人可以給我的,我怎麼能做到這一點使用只是產品上面我在這個問題加上JavaScript的網頁令牌何況,如果他們幫助把解決方案的最新套裝提到一個例子。從我理解的角色是由索賠處理,但我不明白如何添加這些並將它們發回給客戶與令牌。我在互聯網上做了大量的研究,但是我還沒有找到任何好的例子,因爲我認爲大多數情況都是非常新的,沒有多少人有機會探索SPA如何使用這些最新的軟件組件。

當回答這個問題時,請注意,我不是在尋找一個可以告訴社區如何在服務器上設置角色的答案,或者是一個解釋在服務器上提供角色檢查有多重要的答案。 。我想幾乎每個人都知道這一點。我真正認爲將使用的是一些非常詳細的技術建議,包括示例代碼和解釋。爲了保持答案的重點,如果不滿足這種需求的答案不作爲建議答案發布,它可能對每個人都有幫助。

預先感謝您。

+0

你能解釋一下這個「角色是由索賠來處理嗎?聲明是角色的替代方法,但如果您仍想使用角色,請添加聲明,聲明的類型爲[ClaimTypes.Role](http://msdn.microsoft.com/zh-cn/library/system.security.claims.claimtypes .role(v = vs.110).aspx) – LostInComputer

+0

我認爲這可能有所幫助:http://msdn.microsoft.com/en-us/library/hh545448.aspx –

回答

21

簡短的回答你的問題是ApplicationOAuthProvider.CreateProperties方法。它爲你默認創建和下WebApi2 /供應商/ ApplicationOAuthProvider.cs發現,在默認情況下只發送userName

//WepApi2/Providers/ApplicationOAuthProvider.cs 
public static AuthenticationProperties CreateProperties(string userName) 
{ 
    IDictionary<string, string> data = new Dictionary<string, string> 
    { 
     { "userName", userName } 
    }; 
    return new AuthenticationProperties(data); 
} 

我會做以下更新(如果我需要發送更多的用戶數據以後):

public static AuthenticationProperties CreateProperties(string userName, ClaimsIdentity oAuthIdentity) 
{ 
    IDictionary<string, string> data = new Dictionary<string, string> 
    { 
     { "userName", userName}, 
     { "roles",string.Join(",",oAuthIdentity.Claims.Where(c=> c.Type == ClaimTypes.Role).Select(c => c.Value).ToArray())} 

    }; 
    return new AuthenticationProperties(data); 
} 

如果你還沒有到的WebAPI項目發生重大變化,ApplicationOAuthProvider.CreateProperties只在兩個地方引用,只需更新調用代碼傳遞oAuthIdentityuser.UserName一起,你會得到用戶角色一起發送小時訪問令牌響應:

{ 
"access_token": "ZpxAZyYuvCaWgShUz0c_XDLFqpbC0-DIeXl_tuFbr11G-5hzBzSUxFNwNPahsasBD9t6mDDJGHcuEqdvtBT4kDNQXFcjWYvFP7U2Y0EvLS3yejdSvUrh2v1N7Ntz80WKe5G_wy2t11eT0l48dgdyak8lYcl3Nx8D0cgwlQm-pePIanYZatdPFP9q5jzhD-_k9SF-ARTHgf0ePnbvhLBi1MCYQjvfgPKlbBHt0M5qjwGAeFg1IhSVj0gb4g9QTXoiPhRmxGBmjOpGgzxXixavmrpM7cCBFLoR3DCGnIJo6pwT-6VArxlB8-ZyyOZqh_6gGtptd0lIu8iJRUIGwO9HFNkROdoE9T4buwLnhPpWpy9geBjPVwsB1K3xnbch26YbklhxIHVybBxeIVXd17QTw_LjlQ5TJdqpAYfiZ5B9Nx2AFYYYe3--aemh4y1XOIvN", 
"token_type": "bearer", 
"expires_in": 1209599, 
"userName": "MK", 
"roles": "Admin,Public", 
".issued": "Fri, 23 May 2014 17:36:54 GMT", 
".expires": "Fri, 06 Jun 2014 17:36:54 GMT" 
} 

現在你有角色可用,您可以用角條件指令顯示/根據用戶角色隱藏的動作。

如果您需要更多的解釋,請讓我知道。

編輯:

裝飾你的控制器方法與Authorize屬性是有效的,因爲HttpContext.Current.User.Identity實際上是ClaimsIdentity。但不會在應用程序內硬編碼的安全邏輯,我更喜歡使用使用RoleManagerClaimsAuthorizationManager

public ActionResult Secure() 
{ 
    if(!ClaimsPrincipalPermission.CheckAccess("resource", "action")) 
    return new HttpUnauthorizedResult(); 

    ViewBag.Message = "You are allowed to perform action on resource."; 
    return View(); 
} 

角色創建:

RoleManager roleManger = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>()); 
roleManager.Create(new IdentityRole() { Name = "Admin" }); 

角色分配使用UserManager

userManager.AddToRole(user.Id, "Admin"); 
+0

謝謝。我會檢查你的答案並更新評論。 –

+0

MK。 - 謝謝你的建議。我檢查了上面的代碼示例,並且工作正常。然而,我有一個問題,雖然我的用戶被分配了角色,並且他們適合身份表,但這些角色並不存在於聲明中。因此,當我檢查已分配角色的用戶時,我發現他們沒有任何要求。在上述情況下,您的用戶被分配了Admin和Public角色,您是如何分配角色Admin的?你是否也用一個檢查裝飾你的控制器方法以確保用戶在Admin角色中? –

+0

@SamanthaJ角色存在於'ClaimsIdentity'中,我使用修改的'UserManager',我更新了答案以使用默認的asp.net標識2.您也可以直接使用'user.Roles'查詢角色。 至於角色檢查,我更喜歡使用'ClaimsAuthorizationManager' http://msdn.microsoft.com/en-us/library/system.security.claims.claimsauthorizationmanager.checkaccess(v=vs.110).aspx –

0

我有一個非常類似於您的場景,但不使用令牌進行身份驗證,而是使用Identity Server(Thinktecture)來處理我的身份驗證。我的應用程序重定向到身份服務器進行身份驗證,並返回一些非常基本的聲明(用戶名和電子郵件)。只要有人試圖首先瀏覽頁面,就會發生這種情況。一旦用戶通過身份驗證並重定向到我的應用程序,我會再次調用服務器以獲取用戶的權限。這些權限存儲在一個安全服務(AngularJS)中,該服務也暴露了一個「hasPermissions」方法。然後,我使用ng-if來決定是否要顯示頁面的某些部分 - 包括菜單項。事情到這種效果:

var service = { 
    currentUser: ..., 
    isAuthenticated: function() { 
     return ...; 
    }, 
    checkAccess: function(permission) { 
     return service.isAuthenticated() ? 
      !!(service.currentUser.permissions.indexOf(permission) > -1) : false; 
    } 
} 

請記住,所有的所有的權限和HTML元素的人誰決定打開發工具按鈕,並採取偷看可見。在執行任何操作之前,您必須在服務器端執行相同的檢查。我們有一個基於this的自定義授權屬性,該屬性檢查用戶是否擁有執行MVC/WebAPI操作的必要權限,以便在執行任何需要提升的任何事情之前執行簡單案例或在Action或HTTP資源中實際檢查它們特權。

如果你希望客戶端看不到你的網站的任何HTML元素或某一部分,您可以將您的模板,以一個MVC的行動,將身份驗證,然後返回HTML模板或重定向到另一個頁面(不是SPA境界)並在服務器返回響應之前讓它們在服務器上進行身份驗證。

+0

感謝您的建議,但我正在尋找索賠基於角色的解決方案更緊密地集成角色和聲明。 –

+0

角色是索賠。 mithun_daa說的是,您需要向客戶提供索賠(或者在這個例子中,這些索賠給您的權限),以便根據 –

+2

@Martin採取行動 - 這是向客戶提供這些索賠的機制我正在尋找更多信息。最新版本的Identity,WebAPI和Oauth2發生了很大變化。我甚至觀看了Thinktekture架構師的視頻,他提到他不能再推薦將自己的產品用於新的開發,因爲微軟現在擁有更好的解決方案。看起來好像事情不斷髮生變化,我發現沒有什麼好的例子可以說明最好的方法。我希望基於最新版本的軟件提供一個很好的例子。謝謝 –

2

有兩種方式我看到你可以接近你的問題。

  1. 包括通過散列或一個簡單的字符串令牌中的「角色」的信息作爲附加你是一個生成令牌,然後可以解密其上的角。

  2. 看來你想使用ASP.NET Identity系統並在那裏存儲和檢索角色信息。如果是這種情況,您可以通過this post注意「初始化數據庫以創建管理員角色和管理員用戶」部分。

IMO,#1會給你更多的靈活性,你如何存儲和使用您的用戶數據#2你是以下微軟的IdentityUser,儘管它看起來魔術有時,它往往張貼限制,你需要花了解它如何在幕後工作,並使其適用於您的項目。

要更多地瞭解你所創建的項目的WebAPI中挑選「個人用戶帳戶」,你可以去http://www.asp.net/visual-studio/overview/2013/creating-web-projects-in-visual-studio#indauth

0

這裏另外一個答案:

I ñApplicationOAuthProvider.cs

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) 
     { 
      var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>(); 

      ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password); 


      if (user == null) 
      { 
       context.SetError("invalid_grant", "The user name or password is incorrect."); 
       return; 
      } 

只需添加自定義標題!

context.OwinContext.Response.Headers.Add("Roles", userManager.GetRoles(user.Id).ToArray()); 
相關問題