Azure AD v2.0-specifici c необязательные утверждения отсутствуют в ID Token - PullRequest
0 голосов
/ 10 июля 2020

Я пытаюсь добавить необязательные утверждения, используя Microsoft Identity Web - NuGet для аутентификации пользователя в NET Core 3.1 WebApp. Читая документы MS, кажется, что единственные необходимые шаги - это объявить необязательные утверждения в файле манифеста регистрации приложения в Azure. Но при тестировании процесса входа в систему с использованием двух разных приложений (мой собственный код и пример проекта MS) похоже, что необязательные утверждения не добавляются к токену идентификатора при возврате из Azure после успешного входа в систему, то есть их нет при просмотре деталей токена в Debug.

Я не уверен, как это диагностировать и где отследить проблему, т.е. пропущены ли какие-либо необходимые шаги в настройке Azure?

Боковое примечание: просто чтобы подтвердить, что это токен идентификатора jwt, я хочу получать дополнительные утверждения, а НЕ токен доступа jwt, используемый для вызова графика или другой конечной точки веб-API.

Ссылка на документы MS: v2 .0-specifici c необязательный набор утверждений

Ниже приводится выдержка из файла манифеста: (обратите внимание, что я даже объявил "accessTokenAcceptedVersion": 2, учитывая, что я использую необязательные утверждения недоступны в версии 1, и если указанное выше было оставлено с нулевым значением по умолчанию, то Azure будет предполагать, что мы используем устаревшую версию 1 - возможная ошибка)

"accessTokenAcceptedVersion": 2,
"optionalClaims": {
    "idToken": [
        {
            "name": "given_name",
            "source": "user",
            "essential": false,
            "additionalProperties": []
        },
        {
            "name": "family_name",
            "source": "user",
            "essential": false,
            "additionalProperties": []
        }
    ],
    "accessToken": [],
    "saml2Token": []
},

Извлечение из класса запуска:

public void ConfigureServices(IServiceCollection services)
    {
        // Added to original .net core template.
        // ASP.NET Core apps access the HttpContext through the IHttpContextAccessor interface and 
        // its default implementation HttpContextAccessor. It's only necessary to use IHttpContextAccessor 
        // when you need access to the HttpContext inside a service.
        // Example usage - we're using this to retrieve the details of the currrently logged in user in page model actions.
        services.AddHttpContextAccessor();

        // DO NOT DELETE (for now...)
        // This 'Microsoft.AspNetCore.Authentication.AzureAD.UI' library was originally used for Azure Ad authentication 
        // before we implemented the newer Microsoft.Identity.Web and Microsoft.Identity.Web.UI NuGet packages. 
        // Note after implememting the newer library for authetication, we had to modify the _LoginPartial.cshtml file.
        //services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
        //    .AddAzureAD(options => Configuration.Bind("AzureAd", options));

        ///////////////////////////////////

        // Add services required for using options.
        // e.g used for calling Graph Api from WebOptions class, from config file.
        services.AddOptions();

        // Add service for MS Graph API Service Client.
        services.AddTransient<OidcConnectEvents>();

        // Sign-in users with the Microsoft identity platform
        services.AddSignIn(Configuration);

        // Token acquisition service based on MSAL.NET
        // and chosen token cache implementation
        services.AddWebAppCallsProtectedWebApi(Configuration, new string[] { Constants.ScopeUserRead })
            .AddInMemoryTokenCaches();

        // Add the MS Graph SDK Client as a service for Dependancy Injection.
        services.AddGraphService(Configuration);

        ///////////////////////////////////

        // The following lines code instruct the asp.net core middleware to use the data in the "roles" claim in the Authorize attribute and User.IsInrole()
        // See https://docs.microsoft.com/aspnet/core/security/authorization/roles?view=aspnetcore-2.2 for more info.
        services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
        {
            // The claim in the Jwt token where App roles are available.
            options.TokenValidationParameters.RoleClaimType = "roles";
        });

        // Adding authorization policies that enforce authorization using Azure AD roles. Polices defined in seperate classes.
        services.AddAuthorization(options =>
        {
            options.AddPolicy(AuthorizationPolicies.AssignmentToViewLogsRoleRequired, policy => policy.RequireRole(AppRole.ViewLogs));
        });

        ///////////////////////////////////

        services.AddRazorPages().AddMvcOptions(options =>
        {
            var policy = new AuthorizationPolicyBuilder()
                .RequireAuthenticatedUser()
                .Build();
            options.Filters.Add(new AuthorizeFilter(policy));
        }).AddMicrosoftIdentityUI();

        // Adds the service for creating the Jwt Token used for calling microservices.
        // Note we are using our independant bearer token issuer service here, NOT Azure AD
        services.AddScoped<JwtService>(); 
    }

Пример метода PageModel Razor:

public void OnGet()
    {
        var username = HttpContext.User.Identity.Name;
        var forename = HttpContext.User.Claims.FirstOrDefault(c => c.Type == "given_name")?.Value;
        var surname = HttpContext.User.Claims.FirstOrDefault(c => c.Type == "family_name")?.Value;

        _logger.LogInformation("" + username + " requested the Index page");
    }

ОБНОВЛЕНИЕ

Приближаемся к решение, но еще не совсем. Решена пара проблем:

  1. Изначально я создал арендатора в Azure для использования B2 C AD, хотя я больше не использовал B2 C и переключился на Azure AD. . Только когда я удалил клиента и создал новый, я начал замечать, что необязательные утверждения правильно поступают в веб-приложение. После создания нового клиента и назначения типа клиента для использования Azure AD я обнаружил, что меню «Конфигурация токена» теперь доступно для настройки дополнительных утверждений через пользовательский интерфейс, кажется, что изменение манифеста приложения по-прежнему требуется, поскольку ну, как показано выше.

enter image description here

  1. Мне пришлось добавить область «профиля» как тип «делегированный» в разрешения API webapp в Azure.

enter image description here

The final issue still unresolved is that although I can see the claims present during Debug, I cant figure out how to retrieve the claim values.

In the method below, I can see the required claims when using Debug, but can't figure out how to retrieve the values:

public void OnGet()
    {
        var username = HttpContext.User.Identity.Name;

        var forename = HttpContext.User.Claims.FirstOrDefault(c => c.Type == "given_name")?.Value;
        var surname = HttpContext.User.Claims.FirstOrDefault(c => c.Type == "family_name")?.Value;

        _logger.LogInformation("" + username + " requested the Index page");
    }

Debug Screenshots shows the given_name & family_name are present:

enter image description here

введите описание изображения здесь

Я пробовал разные примеры кода, используя принципала претензий, чтобы попытаться получить значения, но у меня ничего не работает. Надеюсь, что эта последняя загадка довольно проста для того, кто знает требуемый синтаксис, как было сказано, теперь у нас есть необходимые необязательные утверждения, просто он не знает, как на самом деле получить значения.

1 Ответ

0 голосов
/ 13 июля 2020

Большое спасибо 'Dhivya G - MSFT Identity' за их помощь (см. Комментарии под моим исходным вопросом). Метод ниже теперь позволяет мне получить доступ к требуемым значениям требований из идентификатора токена, возвращенного Azure после успешного входа в систему.

    public void OnGet()
    {
        var username = HttpContext.User.Identity.Name;

        var forename = HttpContext.User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.GivenName)?.Value;
        var surname = HttpContext.User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Surname)?.Value;

        _logger.LogInformation("" + username + " requested the Index page");
    }
...