Пользовательская авторизация в Asp.net WebApi - какой беспорядок?

Я читаю из нескольких ресурсов (книги и ответы SO) об авторизации в WebApi.

Предположим, я хочу добавить пользовательский атрибут, который разрешает доступ только определенным пользователям:

Случай №1

Я видел такой подход переопределения OnAuthorization, который устанавливает ответ, если что-то не так.

public class AllowOnlyCertainUsers : AuthorizeAttribute
{
 public override void OnAuthorization(HttpActionContext actionContext)
  {
   if ( /*check if user OK or not*/)
   {
     actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
   }
  }
}

Случай №2

Но я также видел этот похожий пример, который также переопределяет OnAuthorization, но с вызовом base:

public override void OnAuthorization(HttpActionContext actionContext) 
{ 
  base.OnAuthorization(actionContext);

    // If not authorized at all, don't bother

    if (actionContext.Response == null)  
     {
      //...
     }
}

Затем вы проверяете, HttpActionContext.Response установлен или нет. Если он не установлен, это означает, что запрос авторизирован и пользователь в порядке

Случай №3

Но я также видел такой подход переопределения IsAuthorized:

public class AllowOnlyCertainUsers : AuthorizeAttribute
{
 protected override bool IsAuthorized(HttpActionContext context)
  {
   if ( /*check if user OK or not*/)
   {
    return true;// or false
   }
  }
}

Дело № 4

И затем я увидел аналогичный пример один, но с вызовом base.IsAuthorized(context):

protected override bool IsAuthorized(HttpActionContext context)
{
 if (something1 && something2 && base.IsAuthorized(context)) //??
 return true;
 return false;
}

Еще одна вещь

И наконец, Доминик сказал здесь:

Вы не должны переопределять OnAuthorization - потому что вам будет отсутствовать обработка [AllowAnonymous].

Вопросы

  • 1) Какие методы следует использовать: IsAuthorized или OnAuthorization? (или когда использовать)

  • 2), когда я должен называть base.IsAuthorized or base.OnAuthorization`?

  • 3) Это как они его построили? что если ответ равен нулю, то все в порядке? (случай № 2)

Н.Б.

Обратите внимание: я использую (и хочу использовать) только AuthorizeAttribute, который уже наследует от AuthorizationFilterAttribute

Почему?

Becuase Я нахожусь на первом этапе: http://www.asp.net/web-api/overview/security/authentication-and-authorization-in-aspnet-web-api

enter image description here

В любом случае, я спрашиваю через расширение атрибута Authorize.

Ответ 1

Какие методы следует использовать: IsAuthorized или OnAuthorization? ( или когда использовать, который)

Расширяется AuthorizationFilterAttribute, если ваша логика авторизации не зависит от установленного идентификатора и ролей. Для авторизации, связанной с пользователем, вы будете расширять и использовать AuthorizeAttribute. В первом случае вы переопределите OnAuthorization. В последнем случае вы переопределите IsAuthorized. Как вы могли видеть из исходного кода этих атрибутов, OnAuthorization помечен как виртуальный, чтобы вы могли переопределить, если вы выходите из AuthorizationFilterAttribute. С другой стороны, метод IsAuthorized помечен как виртуальный AuthorizeAttribute. Я считаю, что это хороший указатель на предполагаемое использование.

когда я должен вызвать base.IsAuthorized или base.OnAuthorization?

Ответ на этот вопрос заключается в том, как работает OO. Если вы переопределяете метод, вы можете либо полностью обеспечить новую реализацию, либо вернуть реалистичность, предоставляемую родителем, и улучшить поведение. Например, возьмите случай IsAuthorized(HttpActionContext). Поведение базового класса заключается в проверке пользователя/роли против того, что указано в фильтре, и установленной идентификации. Скажем, вы хотите сделать все это, но кроме того, вы хотите проверить что-то еще, может быть на основе заголовка запроса или чего-то еще. В этом случае вы можете обеспечить такое переопределение.

protected override bool IsAuthorized(HttpActionContext actionContext)
{
    bool isAuthroized = base.IsAuthorized(actionContext);
    // Here you look at the header and do your additional stuff based on actionContext
    // and store the result in isRequestHeaderOk
    // Then, you can combine the results
    // return isAuthorized && isRequestHeaderOk;
}

Извините, но не понимаю ваш Q3. BTW, фильтр авторизации существует уже давно, и люди используют его для всех видов вещей, а иногда и неправильно.

Еще одна вещь. И, наконец, здесь был этот парень, который сказал: "Ты не следует переопределять OnAuthorization - потому что вам не хватает [AllowAnonymous].

Парень, который сказал, что это Бог контроля доступа - Доминик. Очевидно, это будет правильно. Если вы посмотрите на реализацию OnAuthorization (скопировано ниже),

public override void OnAuthorization(HttpActionContext actionContext)
{
    if (actionContext == null)
    {
        throw Error.ArgumentNull("actionContext");
    }

    if (SkipAuthorization(actionContext))
    {
        return;
    }

    if (!IsAuthorized(actionContext))
    {
        HandleUnauthorizedRequest(actionContext);
    }
}

вызов SkipAuthorization - это часть, обеспечивающая применение фильтров AllowAnonymous, то есть авторизация пропускается. Если вы переопределите этот метод, вы потеряете это поведение. Фактически, если вы решите основать свое разрешение на пользователя/роли, в этот момент вы решили бы получить от AuthorizeAttribute. Только правильная опция, оставленная для вас в этой точке, будет переопределять IsAuthorized, а не уже переопределенный OnAuthorization, хотя технически это возможно сделать.

PS. В ASP.NET Web API существует еще один фильтр, называемый фильтром проверки подлинности. Идея заключается в том, что вы используете это для проверки подлинности и авторизации для авторизации, как указано в названии. Тем не менее, есть много примеров, когда эта граница испорчена. Многие примеры фильтров для автозавершения сделают некоторую аутентификацию. В любом случае, если у вас есть время и вы хотите понять немного больше, взгляните на эту статью MSDN . Отказ от ответственности: он был написан мной.

Ответ 2

Хорошо, мое предложение состоит в том, чтобы сделать следующее, предполагая, что вы используете токены на предъявителя OAuth для защиты вашего веб-API, и вы устанавливаете допустимое время в качестве требования для пользователя, когда вы выдали токен. Вы можете прочитать больше о аутентификации на токене здесь

  • Создать атрибут CustomAuthorizeAttribute, который происходит из AuthorizationFilterAttribute
  • переопределить метод OnAuthorizationAsync и использовать пример кода ниже:

     public class CustomAuthorizeAttribute : AuthorizationFilterAttribute
    {
    
        public override Task OnAuthorizationAsync(HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken)
        {
    
            var principal = actionContext.RequestContext.Principal as ClaimsPrincipal;
    
            if (!principal.Identity.IsAuthenticated)
            {
                return Task.FromResult<object>(null);
            }
    
            var userName = principal.FindFirst(ClaimTypes.Name).Value;
            var userAllowedTime = principal.FindFirst("userAllowedTime").Value;
    
            if (currentTime != userAllowedTime)
            {
                actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized, "Not allowed to access...bla bla");
                return Task.FromResult<object>(null);
            }
    
            //User is Authorized, complete execution
            return Task.FromResult<object>(null);
    
        }
    }
    
  • Теперь в ваших контроллерах вы используете атрибут CustomAuthorize для защиты ваших контроллеров с использованием этой логики авторизации.

Ответ 3

ASP.NET v5 Внедрена совершенно новая система авторизации. Для тех, кто собирается использовать .NET 5, я бы предложил перейти в Microsoft.AspNet.Authorization.

В значительной степени это обертывает беспорядок, вызванный тем, что System.Web.Http.Authorize и System.Web.Mvc.Authorize и других старых реализаций аутентификации.

Он обеспечивает очень хорошую абстракцию типов действий (создание, чтение, обновление, удаление), ресурсов, ролей, претензий, просмотров, пользовательских требований и позволяет создавать пользовательские обработчики, объединяя любой из вышеперечисленных. Кроме того, эти обработчики также могут использоваться в комбинации.

В ASP.NET v5 авторизация теперь предоставляет простую декларативную роль и более богатая политическая модель, где авторизация выражается в требования и обработчики оценивают претензии пользователей против требования. Императивные проверки могут основываться на простых правилах или которые оценивают как идентификацию пользователя, так и свойства ресурс, к которому пользователь пытается получить доступ.