AuthorizeAttribute обходится в Web API при использовании средств форматирования мультимедиа

1

Я создал приложение web api, чтобы открыть API ODATA, для внешнего приложения. Одна из причин для этого заключалась в том, чтобы иметь возможность возвращать разные типы контента, такие как файлы Excel, для тех же данных.

Я использовал специальный Media Formatter для вывода моих данных Excel, однако, я заметил, что когда я его называю, от клиента нет никакой безопасности.

При создании GET, без заголовка ACCEPT, тогда токен маркера OAuth проверяется и доступ либо принимается, либо отменяется. Авторизация устанавливается через [Авторизовать] на контроллере.

Когда я делаю то же GET, с заголовком ACCEPT, чтобы запросить файл Excel, контроллер вызывается независимо от токена, минуя защиту на контроллере.

Я, очевидно, сделал что-то неправильно, однако я не могу понять, что это может быть. Это тот же контроллер, но по какой-то причине он всегда разрешает доступ, когда ACCEPT установлен на поддерживаемый тип носителя.

Ниже приведена сокращенная версия моей настройки.

Owin Startup:

[assembly: OwinStartup(typeof(Rest.Startup))]

namespace Rest
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            ConfigureOAuth(app);
            HttpConfiguration config = new HttpConfiguration();
            WebApiConfig.Register(config);
            app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
            app.UseWebApi(config);
        }

        private void ConfigureOAuth(IAppBuilder app)
        {
            OAuthAuthorizationServerOptions oauthServerOptions = new OAuthAuthorizationServerOptions
            {
                AllowInsecureHttp = true,
                TokenEndpointPath = new PathString("/token"),
                AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
                Provider = new SimpleAuthorisationServerProvider()
            };

            // Token generation
            app.UseOAuthAuthorizationServer(oauthServerOptions);
            app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
        }
    }
}

Вызов в WebApiConfig.Register()

namespace Rest
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            var json = config.Formatters.JsonFormatter;
            json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
            config.Formatters.Remove(config.Formatters.XmlFormatter);

            config.Formatters.Add(new ExcelSimpleFormatter());

            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

            // Configure CORS globally
            var cors = new EnableCorsAttribute(
                origins:"*",
                headers:"*",
                methods:"*");

            config.EnableCors(cors);
        }
    }
}

Мой медиаформат (код удален для экономии места):

namespace Rest.Formatters
{
    public class ExcelSimpleFormatter : BufferedMediaTypeFormatter
    {
        public ExcelSimpleFormatter()
        {
            SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"));
            SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/excel"));
        }

        public override bool CanWriteType(Type type)
        {
            return true;
        }

        public override bool CanReadType(Type type)
        {
            return false;
        }

        public override void WriteToStream(Type type, object value, Stream writeStream, HttpContent content)
        {
            // This gets called regardless of authorization
        }
    }
}

Пример/упрощенный контроллер:

namespace Rest.Controllers
{
    [Authorize]
    public class TestController : ApiController
    {
        private dbSDSContext db = new dbSDSContext();

        // GET: api/Test
        public IQueryable<test> GetTests()
        {
            return db.test;
        }

        // GET: api/Test/5
        [ResponseType(typeof(test))]
        public async Task<IHttpActionResult> GetTest(int id)
        {
            test test = await db.test.FindAsync(id);
            if (test == null)
            {
                return NotFound();
            }

            return Ok(test);
        }

        // PUT: api/Test/5
        [ResponseType(typeof(void))]
        public async Task<IHttpActionResult> PutTest(int id, test test)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            if (id != test.testID)
            {
                return BadRequest();
            }

            db.Entry(test).State = EntityState.Modified;

            try
            {
                await db.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!TestExists(id))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                }
            }

            return StatusCode(HttpStatusCode.NoContent);
        }

        // POST: api/Test
        [ResponseType(typeof(test))]
        public async Task<IHttpActionResult> PostTest(test test)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            db.test.Add(test);
            await db.SaveChangesAsync();

            return CreatedAtRoute("DefaultApi", new { id = test.testID}, test);
        }

        // DELETE: api/Test/5
        [ResponseType(typeof(test))]
        public async Task<IHttpActionResult> DeleteTest(int id)
        {
            test test = await db.test.FindAsync(id);
            if (test == null)
            {
                return NotFound();
            }

            db.test.Remove(test);
            await db.SaveChangesAsync();

            return Ok(test);
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }

        private bool TestExists(int id)
        {
            return db.test.Count(e => e.testID == id) > 0;
        }
    }
}
  • 0
    Странный. Можете ли вы подтвердить это на полностью упрощенном примере?
  • 0
    Я добавил упрощенную версию кода. Контроллер вызывается при установке в заголовке Accept допустимого типа контента, даже анонимного пользователя. Этого не происходит при создании запроса application / json, он правильно запрещает доступ.
Показать ещё 4 комментария
Теги:
asp.net-web-api2
odata

1 ответ

1
Лучший ответ

Ошибка была вызвана неправильным пространством имен в затронутых контроллерах.

При использовании WebAPI убедитесь в использовании:

using System.Web.Http;

и не:

using System.Web.Mvc;

Ещё вопросы

Сообщество Overcoder
Наверх
Меню