Подкласс AuthorizeAttribute с неработающим WebApi возвращает 401?

Я создаю подкласс AuthorizeAttribute, чтобы реализовать аутентификацию по токену, при которой токен передается в заголовке запроса. Я также использую Ninject для IoC. Переопределенный метод OnAuthorization вызывается и проверяет токен, но я все равно получаю ошибку 401.

Любые идеи о том, почему это происходит?

TokenAuthorizationAttribute.cs

public class TokenAuthorisationAttribute : AuthorizeAttribute
{
    private readonly IRepository _repository;


    public TokenAuthorisationAttribute(IRepository repository)
    {
        _repository = repository;
    }

    public override void OnAuthorization(
        HttpActionContext actionContext)
    {

        if (!ValidateToken(actionContext.ControllerContext.Request))
            HandleUnauthorizedRequest(actionContext);

        base.OnAuthorization(actionContext);
    }

    private bool ValidateToken(HttpRequestMessage request)
    {
        const string authenticationToken = "Authentication-Token";

        var token = request.Headers.GetValues(authenticationToken).FirstOrDefault();

        if (token == null)
            return false;

        var device = _repository.FindSingleOrDefault<Device>(x => x.Id.Equals(token));

        if (device == null || !token.Equals(device.Id))
            return false;

        return true;

    }
}

NinjectWebCommon.cs

 public static class NinjectWebCommon 
{
    private static readonly Bootstrapper Bootstrapper = new Bootstrapper();

    /// <summary>
    /// Starts the application
    /// </summary>
    public static void Start() 
    {
        DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
        DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
        Bootstrapper.Initialize(CreateKernel);
    }

    /// <summary>
    /// Stops the application.
    /// </summary>
    public static void Stop()
    {
        Bootstrapper.ShutDown();
    }

    /// <summary>
    /// Creates the kernel that will manage your application.
    /// </summary>
    /// <returns>The created kernel.</returns>
    private static IKernel CreateKernel()
    {
        var kernel = new StandardKernel();
        kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
        kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

        RegisterServices(kernel);

        GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
        return kernel;
    }

    /// <summary>
    /// Load your modules or register your services here!
    /// </summary>
    /// <param name="kernel">The kernel.</param>
    private static void RegisterServices(IKernel kernel)
    {
        var connectionString = ConfigurationManager.ConnectionStrings["MONGOHQ_URL"].ConnectionString;
        var databaseName = ConfigurationManager.AppSettings["Database"];

        kernel.Bind<IRepository>().To<MongoRepository>()
            .WithConstructorArgument("connectionString", connectionString)
            .WithConstructorArgument("databaseName", databaseName);

        kernel.BindHttpFilter<TokenAuthorisationAttribute>(FilterScope.Global);

    }        

person Click Ahead    schedule 19.10.2012    source источник


Ответы (2)


Мне удалось решить эту проблему, переопределив метод IsAuthorized вместо OnAuthorization. Не уверены на 100%, что это правильный подход? Есть мнения??

public class TokenAuthorisationAttribute : AuthorizeAttribute
{
    private readonly IRepository _repository;


    public TokenAuthorisationAttribute(IRepository repository)
    {
        _repository = repository;
    }

    protected override bool IsAuthorized(HttpActionContext actionContext)
    {
        if (actionContext.Request.Headers.Authorization == null)
            return false;

        var authToken = actionContext.Request.Headers.Authorization.Parameter;
        var decodedToken = Encoding.UTF8.GetString(Convert.FromBase64String(authToken));

        var deviceToken = new DeviceToken(decodedToken);


        var device = _repository.FindSingleOrDefault<Device>(x => x.Id.Equals(deviceToken.GetDeviceId()));

        if (device != null)
        {
            HttpContext.Current.User = new GenericPrincipal(new ApiIdentity(device), new string[] {});
            return true;
        }

        return base.IsAuthorized(actionContext);
    }
}
person Click Ahead    schedule 20.10.2012
comment
Согласно stackoverflow.com/questions/15148050/ да, это правильно. - person Colin Young; 06.11.2013

ASP.NET WebAPI — это проект с открытым исходным кодом. Таким образом, вы можете прочитать соответствующие коды здесь:

Есть два факта, которые AuthorizationFilterAttribute принимает во внимание при принятии решения:

  1. Выбрасывает ли OnAuthorization исключение; или
  2. Поле ответа actionContext заполнено;

Либо одно выполнено, остальные действия фильтры и действия являются ярлыками.

Основываясь на вашем коде, мне любопытно, выполняет ли функция HandleUnauthorizedRequest какую-либо из указанных выше операций.

Причина, по которой переопределение IsAuthorized работает, заключается в том, что оно работает на уровне AuthorizeAttribute. Вызов OnAuthorization для перегрузки IsAuthorized и присвоение значения свойству запроса actionContext.

Спасибо, Трой

person Troy Dai    schedule 21.10.2012