Неисправность получения ClaimsPrincipal при использовании EasyAuth для аутентификации против AAD в Azure App Service в веб-приложении Asp.Net Core

У нас есть веб-приложение, построенное на ядре Asp.Net. Он не содержит промежуточного программного обеспечения аутентификации, настроенного в нем.

Мы размещаем в Azure App Service и используем опцию Authentication / Authorization (EasyAuth) для аутентификации с использованием Azure AD.

Аутентификация работает хорошо – мы получаем вставленные необходимые заголовки, и мы можем видеть аутентифицированный идентификатор в /.auth/me. Но свойство HttpContext.User не заполняется.

Является ли это проблемой совместимости для ядра Asp.Net? Или я делаю что-то неправильно?

    Да, это проблема совместимости. К сожалению, ASP.NET Core не поддерживает текущую идентификационную информацию от модуля IIS (например, Easy Auth) к коду приложения. Это означает, что HttpContext.User и аналогичный код не будут работать так же, как с обычным ASP.NET.

    Обходной путь на данный момент заключается в том, чтобы вызывать конечную точку /.auth/me вашего веб-приложения с вашего кода сервера, чтобы получить требования пользователя. Затем вы можете кэшировать эти данные соответствующим образом, используя в качестве ключа кеша значение заголовка запроса x-ms-client-main-id. Вызов /.auth/me должен быть правильно аутентифицирован таким же образом, что вызовы вашего веб-приложения должны быть аутентифицированы (auth cookie или маркер заголовка запроса).

    Я создал настраиваемое промежуточное программное обеспечение, которое заполняет свойство User, пока это не будет устранено командой Azure.

    Он считывает заголовки из Аутентификации Службы App и создает пользователя, который будет распознан [Authorize] и имеет претензию на name .

     // Azure app service will send the x-ms-client-principal-id when authenticated app.Use(async (context, next) => { // Create a user on current thread from provided header if (context.Request.Headers.ContainsKey("X-MS-CLIENT-PRINCIPAL-ID")) { // Read headers from Azure var azureAppServicePrincipalIdHeader = context.Request.Headers["X-MS-CLIENT-PRINCIPAL-ID"][0]; var azureAppServicePrincipalNameHeader = context.Request.Headers["X-MS-CLIENT-PRINCIPAL-NAME"][0]; // Create claims id var claims = new Claim[] { new System.Security.Claims.Claim("http://schemas.microsoft.com/identity/claims/objectidentifier", azureAppServicePrincipalIdHeader), new System.Security.Claims.Claim("name", azureAppServicePrincipalNameHeader) }; // Set user in current context as claims principal var identity = new GenericIdentity(azureAppServicePrincipalIdHeader); identity.AddClaims(claims); // Set current thread user to identity context.User = new GenericPrincipal(identity, null); }; await next.Invoke(); }); 

    Для этого я написал небольшое базовое промежуточное ПО. Это создаст личность, основанную на конечной точке .auth / me. Идентификатор создается в конвейере аутентификации, чтобы атрибуты и политики [authorize] работали с идентификатором.

    Вы можете найти это здесь:

    https://github.com/lpunderscore/azureappservice-authentication-middleware

    или на nuget:

    https://www.nuget.org/packages/AzureAppserviceAuthenticationMiddleware/

    После добавления просто добавьте эту строку в свой запуск:

    app.UseAzureAppServiceAuthentication ();

    Следующий код расшифровывает токен AAD из HTTP-заголовка Azure App Service и заполняет формулу HttpContext.User. Это грубо, поскольку вы хотите кэшировать конфигурацию, а не искать ее по каждому запросу:

      OpenIdConnectConfigurationRetriever r = new OpenIdConnectConfigurationRetriever(); ConfigurationManager configManager = new ConfigurationManager(options.Endpoint, r); OpenIdConnectConfiguration config = await configManager.GetConfigurationAsync(); var tokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKeys = config.SigningKeys.ToList(), ValidateIssuer = true, ValidIssuer = config.Issuer, ValidateAudience = true, ValidAudience = options.Audience, ValidateLifetime = true, ClockSkew = new TimeSpan(0, 0, 10) }; JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler(); ClaimsPrincipal principal = null; SecurityToken validToken = null; string token = context.Request.Headers["X-MS-TOKEN-AAD-ID-TOKEN"]; if (!String.IsNullOrWhiteSpace(token)) { principal = handler.ValidateToken(token, tokenValidationParameters, out validToken); var validJwt = validToken as JwtSecurityToken; if (validJwt == null) { throw new ArgumentException("Invalid JWT"); } if (principal != null) { context.User.AddIdentities(principal.Identities); } } 

    Он работает только для Azure AD. Чтобы поддерживать других поставщиков ID (Facebook, Twitter и т. Д.), Вам нужно будет обнаружить соответствующие заголовки и выяснить, как анализировать токены каждого провайдера. Тем не менее, это должны быть только вариации по вышеуказанной теме.

    Давайте будем гением компьютера.