Azure AD B2C - 角色管理

时间:2017-08-25 16:29:56

标签: c# asp.net-mvc azure asp.net-mvc-5 azure-ad-b2c

我有一个与Azure AD B2C连接的Asp.NET MVC应用程序。

在管理员设置中,我创建了一个管理员组:

enter image description here

在我的代码中,我想使用[Authorize(Roles = "Administrator")]

使用常规Azure Active Directory,它很容易添加(只需3行代码)。但对于Azure AD B2C,我找不到任何有用的教程或示例。也许你可以告诉我我需要修改什么。

这是我的Startup.Auth.cs的ConfigureAuth方法

public void ConfigureAuth(IAppBuilder app)
{
    app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

    app.UseCookieAuthentication(new CookieAuthenticationOptions());

    app.UseOpenIdConnectAuthentication(
        new OpenIdConnectAuthenticationOptions
        {
            // Generate the metadata address using the tenant and policy information
            MetadataAddress = String.Format(AadInstance, Tenant, DefaultPolicy),

            // These are standard OpenID Connect parameters, with values pulled from web.config
            ClientId = ClientId,
            RedirectUri = RedirectUri,
            PostLogoutRedirectUri = RedirectUri,

            // Specify the callbacks for each type of notifications
            Notifications = new OpenIdConnectAuthenticationNotifications
            {
                RedirectToIdentityProvider = OnRedirectToIdentityProvider,
                AuthorizationCodeReceived = OnAuthorizationCodeReceived,
                AuthenticationFailed = OnAuthenticationFailed,
            },

            // Specify the claims to validate
            TokenValidationParameters = new TokenValidationParameters
            {
                NameClaimType = "name"
            },

            // Specify the scope by appending all of the scopes requested into one string (separated by a blank space)
            Scope = $"openid profile offline_access {ReadTasksScope} {WriteTasksScope}"
        }
    );
}

1 个答案:

答案 0 :(得分:15)

Azure AD B2C尚未在其发送给应用程序的令牌中包含组声明,因此您无法采用与Azure AD中概述的相同方法(其中包含组中的声明)令牌)。

您可以在Azure AD B2C反馈论坛中投票支持此功能:Get user membership groups in the claims with Azure AD B2C

话虽如此,您可以在此应用程序中做一些额外的工作,让它手动检索该组声称的这些声明并将其注入令牌

首先,注册一个单独的应用程序,该应用程序将调用Microsoft Graph以检索组声明

  1. 转到https://apps.dev.microsoft.com
  2. 使用应用程序权限创建应用程序: Directory.Read.All
  3. 点击生成新密码
  4. 添加应用程序密钥
  5. 添加平台并选择网络并为其指定任何重定向URI(例如https://yourtenant.onmicrosoft.com/groups
  6. 导航至https://login.microsoftonline.com/YOUR_TENANT.onmicrosoft.com/adminconsent?client_id=YOUR_CLIENT_ID&state=12345&redirect_uri=YOUR_REDIRECT_URI
  7. 同意此应用程序

    然后,您需要在OnAuthorizationCodeReceived处理程序right after redeeming the code内添加以下代码:

    var authority = $"https://login.microsoftonline.com/{Tenant}";
    var graphCca = new ConfidentialClientApplication(GraphClientId, authority, GraphRedirectUri, new ClientCredential(GraphClientSecret), userTokenCache, null);
    string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
    
    try
    {
        AuthenticationResult authenticationResult = await graphCca.AcquireTokenForClientAsync(scopes);
        string token = authenticationResult.AccessToken;
    
        using (var client = new HttpClient())
        {
            string requestUrl = $"https://graph.microsoft.com/v1.0/users/{signedInUserID}/memberOf?$select=displayName";
    
            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUrl);
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
    
            HttpResponseMessage response = await client.SendAsync(request);
            var responseString = await response.Content.ReadAsStringAsync();
    
            var json = JObject.Parse(responseString);
    
            foreach (var group in json["value"])
                notification.AuthenticationTicket.Identity.AddClaim(new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Role, group["displayName"].ToString(), System.Security.Claims.ClaimValueTypes.String, "Graph"));
    
            //TODO: Handle paging. 
            // https://developer.microsoft.com/en-us/graph/docs/concepts/paging
            // If the user is a member of more than 100 groups, 
            // you'll need to retrieve the next page of results.
        }
    } catch (Exception ex)
    {
        //TODO: Handle
        throw;
    }