Как принудительно выполнить повторную проверку подлинности между веб-приложением ASP Net Core 2.0 MVC и Azure AD - PullRequest
0 голосов
/ 30 мая 2018

У меня есть веб-приложение ASP.Net Core MVC, которое использует Azure AD для проверки подлинности.Я только что получил новое требование, чтобы вынудить пользователя выполнить повторную проверку подлинности перед вводом конфиденциальной информации (кнопка для ввода этой новой информации вызывает действие контроллера, которое инициализирует новую модель представления и возвращает частичное представление в режим начальной загрузки).

Я следовал этой статье, которая является отличным руководством для достижения именно этого требования.Мне пришлось внести некоторые изменения, чтобы заставить его работать с ASP.Net Core 2.0, что я считаю правильным, однако мои проблемы заключаются в следующем ...

  1. Добавление декорации фильтра ресурсов "[RequireReauthentication (0)] "для моего контроллера действие работает, однако передача значения 0 означает, что код никогда не достигает команды await.next () внутри фильтра.Если я изменяю значение параметра на 30, это работает, но кажется очень произвольным.Каким должно быть это значение?

  2. Повторная аутентификация работает при вызове действия контроллера, которое возвращает полный просмотр.Однако, когда я вызываю действие из ajax-запроса, который возвращает партиал в модал начальной загрузки, он завершается неудачей, прежде чем загружать модал с помощью

Ответ на предпечатный запрос не проходит контроль доступапроверка: в запрашиваемом ресурсе отсутствует заголовок «Access-Control-Allow-Origin».Origin 'https://localhost:44308', следовательно, не разрешен доступ

Это похоже на проблему CORS, но я не знаю, почему это будет работать при прохождении стандартного процесса mvc, а не при вызовеиз jquery.Добавление

services.AddCors ();

app.UseCors (builder => builder.WithOrigins ("https://login.microsoftonline.com"));

в мой файл запуска)не имеет значения. В чем может быть проблема здесь?

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    // Ommitted for clarity...

    services.AddAuthentication(sharedOptions =>
    {
        sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
    })
    .AddAzureAd(options => Configuration.Bind("AzureAd", options))
    .AddCookie();

    services.AddCors();

    // Ommitted for clarity...
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    // Ommitted for clarity...

    app.UseCors(builder => builder.WithOrigins("https://login.microsoftonline.com"));

    app.UseStaticFiles();

    app.UseAuthentication();

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

AzureAdAuthenticationBuilderExtensions.cs

public static class AzureAdAuthenticationBuilderExtensions
{        
    public static AuthenticationBuilder AddAzureAd(this AuthenticationBuilder builder)
        => builder.AddAzureAd(_ => { });

    public static AuthenticationBuilder AddAzureAd(this AuthenticationBuilder builder, Action<AzureAdOptions> configureOptions)
    {
        builder.Services.Configure(configureOptions);
        builder.Services.AddSingleton<IConfigureOptions<OpenIdConnectOptions>, ConfigureAzureOptions>();
        builder.AddOpenIdConnect(options =>
        {
            options.ClaimActions.Remove("auth_time");
            options.Events = new OpenIdConnectEvents
            {
                OnRedirectToIdentityProvider = RedirectToIdentityProvider
            };
        });
        return builder;
    }

    private static Task RedirectToIdentityProvider(RedirectContext context)
    {
        // Force reauthentication for sensitive data if required
        if (context.ShouldReauthenticate())
        {
            context.ProtocolMessage.MaxAge = "0"; // <time since last authentication or 0>;
        }
        else
        {
            context.Properties.RedirectUri = new PathString("/Account/SignedIn");
        }

        return Task.FromResult(0);
    }

    internal static bool ShouldReauthenticate(this RedirectContext context)
    {
        context.Properties.Items.TryGetValue("reauthenticate", out string reauthenticate);
        bool shouldReauthenticate = false;

        if (reauthenticate != null && !bool.TryParse(reauthenticate, out shouldReauthenticate))
        {
            throw new InvalidOperationException($"'{reauthenticate}' is an invalid boolean value");
        }

        return shouldReauthenticate;
    }

    // Ommitted for clarity...
}

RequireReauthenticationAttribute.cs

public class RequireReauthenticationAttribute : Attribute, IAsyncResourceFilter
{
    private int _timeElapsedSinceLast;
    public RequireReauthenticationAttribute(int timeElapsedSinceLast)
    {
        _timeElapsedSinceLast = timeElapsedSinceLast;
    }
    public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next)
    {
        var foundAuthTime = int.TryParse(context.HttpContext.User.FindFirst("auth_time")?.Value, out int authTime);
        var ts = DateTimeOffset.UtcNow.ToUnixTimeSeconds();

        if (foundAuthTime && ts - authTime < _timeElapsedSinceLast)
        {
            await next();
        }
        else
        {
            var state = new Dictionary<string, string> { { "reauthenticate", "true" } };
            await AuthenticationHttpContextExtensions.ChallengeAsync(context.HttpContext, OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties(state));
        }
    }
}

CreateNote.cs

[HttpGet]
[RequireReauthentication(0)]
public IActionResult CreateNote(int id)
{
    TempData["IsCreate"] = true;
    ViewData["PostAction"] = "CreateNote";
    ViewData["PostRouteId"] = id;
    var model = new NoteViewModel
    {
        ClientId = id
    };
    return PartialView("_Note", model);
}

Просмотр бритвы (фрагмент)

<a asp-controller="Client" asp-action="CreateNote" asp-route-id="@ViewData["ClientId"]" id="client-note-get" data-ajax="true" data-ajax-method="get" data-ajax-update="#client-note-modal-content" data-ajax-mode="replace" data-ajax-success="ShowModal('#client-note-modal', null, null);" data-ajax-failure="AjaxFailure(xhr, status, error, false);"></a>

Вся помощь оценена. Спасибо

1 Ответ

0 голосов
/ 30 мая 2018

Проблема с CORS отсутствует в вашем приложении.Ваш AJAX-вызов пытается выполнить перенаправление аутентификации в Azure AD, которое не будет работать.

Вместо этого вы можете выполнить функцию RedirectToIdentityProvider, проверьте, является ли запрос запросом AJAX.Если это так, сделайте так, чтобы он возвращал код состояния 401, без перенаправления.

Тогда JS на стороне клиента должен определить код состояния и выполнить перенаправление, которое вызывает аутентификацию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...