Как вы справляетесь с неудачной аутентификацией пользователя в пользовательском AuthenticationHandler? - PullRequest
0 голосов
/ 06 ноября 2019

У меня есть сценарий, в котором приложение должно аутентифицировать пользователя, вызывая API и отправляя маркер пользователя для проверки личности пользователя. Я начал работать над пользовательским обработчиком аутентификации на основе следующих руководств:

Учебник 1

Учебник 2

У меня естьочень простой пример, который прямо сейчас просто не проходит аутентификацию, просто чтобы убедиться, что она работает:

public class SoleAuthenticationHandler : AuthenticationHandler<SoleAuthenticationOptions>
{
    private readonly ISoleApiService _soleApiService;

    public SoleAuthenticationHandler(
        IOptionsMonitor<SoleAuthenticationOptions> options, 
        ILoggerFactory logger, 
        UrlEncoder encoder, 
        ISystemClock clock, ISoleApiService soleApiService) 
        : base(options, logger, encoder, clock)
    {
        _soleApiService = soleApiService;
    }

    protected override Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        return Task.FromResult(AuthenticateResult.Fail("You are not authorized to access this resource."));
    }
}

Это работает так, как задумано, действия контроллера, украшенные атрибутом [Authorize], перехватываются и выдается 401. Мои вопросы следующие:

  1. Как мне справиться с 401, когда это произойдет? Например, скажем, я хочу перенаправить пользователя на дружественную страницу с надписью «Вы не авторизованы, пожалуйста, войдите». Это сделано в обработчике или в другом месте? Каков надлежащий процесс здесь? Если посмотреть на документы Microsoft для AuthenticationHandler , существует метод BuildRedirectUri, но предоставление этого метода с помощью URI ничего не меняет - страница все равно возвращает 401.
  2. В том виде, в каком он сейчас находится вЧтобы это работало, мне нужно украсить контроллеры / действия атрибутом [Authorize]. Есть ли способ сделать это глобально, чтобы мне не нужно было специально авторизовать каждый контроллер и / или действие?

1 Ответ

0 голосов
/ 12 ноября 2019

У нас были / есть страницы customErrors в веб-формах ASP.NET и MVC 5.x для автоматического перенаправления пользователей на указанные страницы ошибок при выдаче определенного кода состояния:

<customErrors mode="On" defaultRedirect="error">
        <error statusCode="404" redirect="error/notfound" />
        <error statusCode="403" redirect="error/forbidden" />
</customErrors>

Здесь, вВ ASP.NET Core мы можем смоделировать эти страницы следующим образом:

Сначала добавьте новый ErrorController для обработки определенных statusCodes (идентификаторы здесь), а затем верните пользовательские представления для различных условий:

public class ErrorController : Controller
    {
        private readonly ILogger<ErrorController> _logger;

        public ErrorController(ILogger<ErrorController> logger)
        {
            _logger = logger;
        }

        public IActionResult Index(int? id)
        {
            var logBuilder = new StringBuilder();

            var statusCodeReExecuteFeature = HttpContext.Features.Get<IStatusCodeReExecuteFeature>();
            logBuilder.AppendLine($"Error {id} for {Request.Method} {statusCodeReExecuteFeature?.OriginalPath ?? Request.Path.Value}{Request.QueryString.Value}\n");

            var exceptionHandlerFeature = this.HttpContext.Features.Get<IExceptionHandlerFeature>();
            if (exceptionHandlerFeature?.Error != null)
            {
                var exception = exceptionHandlerFeature.Error;
                logBuilder.AppendLine($"<h1>Exception: {exception.Message}</h1>{exception.StackTrace}");
            }

            foreach (var header in Request.Headers)
            {
                var headerValues = string.Join(",", value: header.Value);
                logBuilder.AppendLine($"{header.Key}: {headerValues}");
            }
            _logger.LogError(logBuilder.ToString());

            if (id == null)
            {
                return View("Error");
            }

            switch (id.Value)
            {
                case 401:
                case 403:
                    return View("AccessDenied");
                case 404:
                    return View("NotFound");

                default:
                    return View("Error");
            }
        }
    }

Теперь пришло время подключить этот контроллер к встроенному промежуточному программному обеспечению обработки ошибок ASP.NET Core:

public void Configure(IApplicationBuilder app)
        {
            if (env.IsDevelopment())
            {
                app.UseDatabaseErrorPage();
                app.UseDeveloperExceptionPage();
            }
            app.UseExceptionHandler("/error/index/500");
            app.UseStatusCodePagesWithReExecute("/error/index/{0}");

По поводу вашего второго вопроса, просто определите свой фильтр / атрибут Authorize глобально .

...