Я создал приложение 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;
}
}
}
Ошибка была вызвана неправильным пространством имен в затронутых контроллерах.
При использовании WebAPI убедитесь в использовании:
using System.Web.Http;
и не:
using System.Web.Mvc;