2016-10-28 147 views
16

我想弄清楚如何授權在Azure Active Directory B2C中使用組。我可以通過用戶授權,例如:在Azure Active Directory中按組授權B2C

[Authorize(Users="Bill")] 

但是這不是很有效,我看到很少用例。另一種解決方案是通過角色授權。然而由於某種原因,似乎並不合適。例如,如果我給用戶角色「全局管理員」並嘗試:

[Authorize(Roles="Global Admin")] 

它不起作用。有沒有辦法通過組或角色進行授權?

回答

11

這會起作用,但是您已經在認證邏輯中編寫了幾行代碼,以實現您的目標。

首先,您必須區分Azure AD(B2C)中的RolesGroups

User Role非常具體,只在Azure AD(B2C)本身內有效。該角色定義了用戶擁有的Azure AD內部的許可權限

Group(或Security Group)定義了可以暴露給外部應用程序的用戶組成員身份。外部應用程序可以模型基於角色的訪問控制上安全組。是的,我知道這可能聽起來有點混亂,但事實就是如此。

因此,您的第一步是在Azure AD B2C中爲Groups建模 - 您必須創建組並手動將用戶分配給這些組。你可以做的是,在Azure的門戶網站(https://portal.azure.com/):

enter image description here

然後,回到你的應用程序,你將不得不編寫一個位,並要求Azure AD B2C Graph API用戶成員一旦用戶成功驗證。您可以使用this sample來獲取如何獲得用戶組成員身份的啓發。最好在其中一個OpenID通知中執行此代碼(即SecurityTokenValidated),並將用戶角色添加到ClaimsPrincipal。

一旦將ClaimsPrincipal更改爲具有Azure AD安全組和「角色聲明」值,您就可以在角色功能中使用Authrize屬性。這確實是5-6行代碼。

最後,您可以在此處投票選擇此功能:https://feedback.azure.com/forums/169401-azure-active-directory/suggestions/1-get-user-membership-groups-in-the-claims-with-ad-b以獲取組成員資格聲明,而無需查詢Graph API。

+0

你能否顯示那些5-6行?我一直在努力拼湊這個問題的答案几天,現在我已經有超過100行代碼(並且它還沒有工作!)。如果像5或6行那樣簡單地連接通知,查詢用戶組數據的圖形,並將這些組添加到ClaimsPrincipal角色,我顯然會咆哮錯誤的樹。我真的很感激一些重定向! – reidLinden

25

從Azure AD獲取用戶的組成員身份需要的不僅僅是「幾行代碼」,所以我認爲我會分享最終爲我工作的工作,以便爲其他人節省幾天的費用 - 拉和頭撞。

首先,讓我們通過添加下列依賴於project.json:

"dependencies": { 
    ... 
    "Microsoft.IdentityModel.Clients.ActiveDirectory": "3.13.8", 
    "Microsoft.Azure.ActiveDirectory.GraphClient": "2.0.2" 
} 

第一個是必要的,因爲我們需要爲了驗證我們的應用程序爲它能夠訪問AAD圖形API。 第二個是我們將用來查詢用戶成員資格的Graph API客戶端庫。 不言而喻,這些版本僅在撰寫本文時有效,並可能在未來發生變化。

接下來,啓動類的配置()方法,也許我們配置ID連接的身份驗證之前,我們創建了圖形API客戶端如下:

var authContext = new AuthenticationContext("https://login.microsoftonline.com/<your_directory_name>.onmicrosoft.com"); 
var clientCredential = new ClientCredential("<your_b2c_app_id>", "<your_b2c_secret_app_key>"); 
const string AAD_GRAPH_URI = "https://graph.windows.net"; 
var graphUri = new Uri(AAD_GRAPH_URI); 
var serviceRoot = new Uri(graphUri, "<your_directory_name>.onmicrosoft.com"); 
this.aadClient = new ActiveDirectoryClient(serviceRoot, async() => await AcquireGraphAPIAccessToken(AAD_GRAPH_URI, authContext, clientCredential)); 

警告:不要硬編碼的祕密的應用程序密鑰,但保持在一個安全的地方。那麼,你已經知道了,對吧? :)

當客戶端需要獲取身份驗證令牌時,我們提交給AD客戶端構造函數的異步AcquireGraphAPIAccessToken()方法將根據需要進行調用。下面就是該方法的樣子:

private async Task<string> AcquireGraphAPIAccessToken(string graphAPIUrl, AuthenticationContext authContext, ClientCredential clientCredential) 
{ 
    AuthenticationResult result = null; 
    var retryCount = 0; 
    var retry = false; 

    do 
    { 
     retry = false; 
     try 
     { 
      // ADAL includes an in-memory cache, so this will only send a request if the cached token has expired 
      result = await authContext.AcquireTokenAsync(graphAPIUrl, clientCredential); 
     } 
     catch (AdalException ex) 
     { 
      if (ex.ErrorCode == "temporarily_unavailable") 
      { 
       retry = true; 
       retryCount++; 
       await Task.Delay(3000); 
      } 
     } 
    } while (retry && (retryCount < 3)); 

    if (result != null) 
    { 
     return result.AccessToken; 
    } 

    return null; 
} 

注意,它具有處理瞬態條件下,您可能要調整到應用程序的需求,內置重試機制。

現在我們已經關注了應用程序認證和AD客戶端設置,我們可以繼續使用OpenIdConnect事件來最終使用它。 早在那裏我們會通常要求app.UseOpenIdConnectAuthentication()創造OpenIdConnectOptions實例的配置()方法中,我們添加一個事件處理程序OnTokenValidated事件:

new OpenIdConnectOptions() 
{ 
    ...   
    Events = new OpenIdConnectEvents() 
    { 
     ... 
     OnTokenValidated = SecurityTokenValidated 
    }, 
}; 

該事件被觸發時,訪問令牌的signing-已經獲得,驗證並建立了用戶身份。 (不要與調用AAD Graph API所需的應用程序自己的訪問令牌混淆!) 它看起來像是查詢用戶組成員資格的Graph API的好地方,並以附加聲明的形式將這些組添加到標識中:

private Task SecurityTokenValidated(TokenValidatedContext context) 
{ 
    return Task.Run(async() => 
    { 
     var oidClaim = context.SecurityToken.Claims.FirstOrDefault(c => c.Type == "oid"); 
     if (!string.IsNullOrWhiteSpace(oidClaim?.Value)) 
     { 
      var pagedCollection = await this.aadClient.Users.GetByObjectId(oidClaim.Value).MemberOf.ExecuteAsync(); 

      do 
      { 
       var directoryObjects = pagedCollection.CurrentPage.ToList(); 
       foreach (var directoryObject in directoryObjects) 
       { 
        var group = directoryObject as Group; 
        if (group != null) 
        { 
         ((ClaimsIdentity)context.Ticket.Principal.Identity).AddClaim(new Claim(ClaimTypes.Role, group.DisplayName, ClaimValueTypes.String)); 
        } 
       } 
       pagedCollection = pagedCollection.MorePagesAvailable ? await pagedCollection.GetNextPageAsync() : null; 
      } 
      while (pagedCollection != null); 
     } 
    }); 
} 

此處使用的是角色聲明類型,但您可以使用自定義聲明類型。

做完上面的,如果你使用ClaimType.Role,所有你需要做的是裝飾你的控制器類或方法,像這樣:

[Authorize(Role = "Administrators")] 

那是當然的,只要你有一在B2C中配置了一個顯示名稱爲「管理員」的指定組。

但是,如果您選擇使用自定義聲明類型,你需要通過在ConfigureServices加入這樣的事情()方法,定義基於聲明類型的授權策略,例如:

services.AddAuthorization(options => options.AddPolicy("ADMIN_ONLY", policy => policy.RequireClaim("<your_custom_claim_type>", "Administrators"))); 

再裝飾一個特權控制器類或方法如下:

[Authorize(Policy = "ADMIN_ONLY")] 

好,是我們做了嗎? - 呃,不完全是。

如果您運行了應用程序並嘗試登錄,則會從Graph API中得到一個異常,聲稱「權限不足以完成操作」。 這可能並不明顯,但是當您的應用程序使用其app_id和app_key成功驗證AD時,它不具備從AD讀取用戶詳細信息所需的權限。 爲了授予應用程序,訪問,我選擇使用Azure Active Directory Module for PowerShell

下面的腳本的伎倆對我來說:

$tenantGuid = "<your_tenant_GUID>" 
$appID = "<your_app_id>" 

$userVal = "<admin_user>@<your_AD>.onmicrosoft.com" 
$pass = "<admin password in clear text>" 
$Creds = New-Object System.Management.Automation.PsCredential($userVal, (ConvertTo-SecureString $pass -AsPlainText -Force)) 

Connect-MSOLSERVICE -Credential $Creds 
$msSP = Get-MsolServicePrincipal -AppPrincipalId $appID -TenantID $tenantGuid 

$objectId = $msSP.ObjectId 

Add-MsolRoleMember -RoleName "Company Administrator" -RoleMemberType ServicePrincipal -RoleMemberObjectId $objectId 

而現在我們終於完成了! 「幾行代碼」的情況如何? :)

+1

這是一篇優秀的文章。謝謝! – Dan

+0

這樣的美麗,如此清晰,多sw!! – Molibar

+0

@ChristerBrannstrom謝謝! - 我很高興它幫助了幾個人。 –

2

我implmented這是寫的,但在5月2017年線

((ClaimsIdentity)context.Ticket.Principal.Identity).AddClaim(new Claim(ClaimTypes.Role, group.DisplayName, ClaimValueTypes.String)); 

需求的改變,以

((ClaimsIdentity)context.Ticket.Principal.Identity).AddClaim(new Claim(ClaimTypes.Role, group.DisplayName)); 

,使其與最新的庫

偉大的工作工作給作者

此外,如果您有與Connect-MsolService givin問題g壞的用戶名和密碼更新到最新的庫

相關問題