2015-05-29 141 views
0

我有一個使用Azure AAD授權的asp.net mvc應用程序。該應用程序是基於此github上例如:asp.net上的自定義授權屬性mvc

https://github.com/dushyantgill/VipSwapper/tree/master/TrainingPoint

這個程序有一個自定義屬性授權

public class AuthorizeUserAttribute : AuthorizeAttribute 
    { 
     protected override void HandleUnauthorizedRequest(AuthorizationContext ctx) 
     { 
      if (!ctx.HttpContext.User.Identity.IsAuthenticated) 
       base.HandleUnauthorizedRequest(ctx); 
      else 
      { 
       ctx.Result = new ViewResult { ViewName = "Error", ViewBag = { message = "Unauthorized." } }; 
       ctx.HttpContext.Response.StatusCode = 403; 
      } 
     } 
    } 

然而,這似乎很奇怪我。

我有一個控制器是這樣的:

public class GlobalAdminController : Controller 
    { 
     // GET: GlobalAdmin 
     [AuthorizeUser(Roles = "admin")] 
     public ActionResult Index() 
     { 
      return View(); 
     } 
    } 

正如你可以看到自定義屬性是用來那裏,而是採取在自定義屬性的代碼更深入的瞭解。 顯然,在if和else兩個請求都沒有通過認證。

現在看看這個截圖。

沒有意義嗎? http://screencast.com/t/obqXHZJj0iNG

問題是,我應該怎麼做才能讓用戶執行控制器?

更新1: 在我的身份驗證流程,我有以下

public void ConfigureAuth(IAppBuilder app) 
     { 
      // configure the authentication type & settings 
      app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType); 
      app.UseCookieAuthentication(new CookieAuthenticationOptions()); 

      // configure the OWIN OpenId Connect options 
      app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions 
      { 
       ClientId = SettingsHelper.ClientId, 
       Authority = SettingsHelper.AzureADAuthority, 
       Notifications = new OpenIdConnectAuthenticationNotifications() 
       { 
        // when an auth code is received... 
        AuthorizationCodeReceived = (context) => { 
         // get the OpenID Connect code passed from Azure AD on successful auth 
         string code = context.Code; 

         // create the app credentials & get reference to the user 
         ClientCredential creds = new ClientCredential(SettingsHelper.ClientId, SettingsHelper.ClientSecret); 
         string userObjectId = context.AuthenticationTicket.Identity.FindFirst(System.IdentityModel.Claims.ClaimTypes.NameIdentifier).Value; 

         // use the ADAL to obtain access token & refresh token... 
         // save those in a persistent store... 
         EfAdalTokenCache sampleCache = new EfAdalTokenCache(userObjectId); 
         AuthenticationContext authContext = new AuthenticationContext(SettingsHelper.AzureADAuthority, sampleCache); 

         // obtain access token for the AzureAD graph 
         Uri redirectUri = new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)); 
         AuthenticationResult authResult = authContext.AcquireTokenByAuthorizationCode(code, redirectUri, creds, SettingsHelper.AzureAdGraphResourceId); 

         if (GraphUtil.IsUserAADAdmin(context.AuthenticationTicket.Identity)) 
          context.AuthenticationTicket.Identity.AddClaim(new Claim("roles", "admin")); 

         // successful auth 
         return Task.FromResult(0); 
        }, 
        AuthenticationFailed = (context) => { 
         context.HandleResponse(); 
         return Task.FromResult(0); 
        } 
       }, 
       TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters 
       { 
        ValidateIssuer = false 
       } 
      }); 
     } 

檢查特地IsAADAdmin方法調用

/// <summary> 
     /// The global administrators and user account administrators of the directory are automatically assgined the admin role in the application. 
     /// This method determines whether the user is a member of the global administrator or user account administrator directory role. 
     /// RoleTemplateId of Global Administrator role = 62e90394-69f5-4237-9190-012177145e10 
     /// RoleTemplateId of User Account Administrator role = fe930be7-5e62-47db-91af-98c3a49a38b1 
     /// </summary> 
     /// <param name="objectId">The objectId of user or group that currently has access.</param> 
     /// <returns>String containing the display string for the user or group.</returns> 
     public static bool IsUserAADAdmin(ClaimsIdentity Identity) 
     { 
      string tenantId = Identity.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value; 
      string signedInUserID = Identity.FindFirst(System.IdentityModel.Claims.ClaimTypes.NameIdentifier).Value; 
      string userObjectID = Identity.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value; 

      ClientCredential credential = new ClientCredential(SettingsHelper.ClientId, SettingsHelper.ClientSecret); 

      // initialize AuthenticationContext with the token cache of the currently signed in user, as kept in the app's EF DB 
      AuthenticationContext authContext = new AuthenticationContext(SettingsHelper.AzureADAuthority, new EfAdalTokenCache(signedInUserID)); 

      AuthenticationResult result = authContext.AcquireTokenSilent(
       SettingsHelper.AzureAdGraphResourceId, credential, new UserIdentifier(userObjectID, UserIdentifierType.UniqueId)); 

      HttpClient client = new HttpClient(); 

      string doQueryUrl = string.Format("{0}/{1}/users/{2}/memberOf?api-version={3}", 
       SettingsHelper.AzureAdGraphResourceId, tenantId, 
       userObjectID, SettingsHelper.GraphAPIVersion); 

      HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, doQueryUrl); 
      request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken); 
      HttpResponseMessage response = client.SendAsync(request).Result; 

      if (response.IsSuccessStatusCode) 
      { 
       var responseContent = response.Content; 
       string responseString = responseContent.ReadAsStringAsync().Result; 
       var memberOfObjects = (System.Web.Helpers.Json.Decode(responseString)).value; 

       if (memberOfObjects != null) 
        foreach (var memberOfObject in memberOfObjects) 
         if (memberOfObject.objectType == "Role" && (
          memberOfObject.roleTemplateId.Equals("62e90394-69f5-4237-9190-012177145e10", StringComparison.InvariantCultureIgnoreCase) || 
          memberOfObject.roleTemplateId.Equals("fe930be7-5e62-47db-91af-98c3a49a38b1", StringComparison.InvariantCultureIgnoreCase))) 
          return true; 
      } 

      return false; 
     } 

我100%肯定的用戶是在管理作用,因爲當我調試它返回true和聲明創建

更新2: 在調試我檢查了User.Claims和角色admin在那裏。 所以我不知道每個角色本授權如何與User.IsInRole

http://screencast.com/t/zUbwbpzn55qb

+0

您發佈的代碼只在用戶未被授權時被調用,否則它使用AuthorizeAttribute的默認行爲。所以我不明白你的問題是什麼。 –

+0

身份驗證和授權是兩個不同的事情。用戶可能登錄但不是管理員,因此他已通過身份驗證但未獲得授權。您需要將該用戶作爲管理員添加到「webpages_UsersInRoles」表中以供他授權。 –

+0

我確信用戶已經通過身份驗證,並且它在角色admin中,請參閱Update1,代碼來自我提供的示例代碼,但我也將其粘貼到此處以提供更多解釋 –

回答

3

埃斯特萬,你似乎已經錯過了設置在ConfigureAuth實施中的作用要求類型。請參閱樣本的第55行:https://github.com/dushyantgill/VipSwapper/blob/master/TrainingPoint/App_Start/Startup.Auth.cs#L55。一旦你這樣做User.IsInRole()和授權屬性將正常工作。

Regd實現了自定義授權屬性 - ASP.net有一個錯誤,它返回一個401錯誤(而不是403)授權失敗(將認證用戶置於IdP無限循環中)。這個自定義授權屬性修復了這個問題。

希望有所幫助。

再見。

+0

非常感謝,解決了這個問題。我相信我們會保持聯繫的其他問題。 –

0

爲角色聲明類型http://schemas.microsoft.com/ws/2008/06/identity/claims/role(你可以通過快捷鍵使用ClaimTypes.Rolehere)的作品。

我相信你ConfigureAuth類應該將其改爲:

if (GraphUtil.IsUserAADAdmin(context.AuthenticationTicket.Identity)) 
          context.AuthenticationTicket.Identity.AddClaim(new Claim("roles", "admin")); 

要這樣:

​​