C# 使用媒体格式化程序时在Web API中绕过的AuthorizeAttribute
我创建了一个web api应用程序,将ODataAPI公开给前端应用程序。这样做的原因之一是能够为相同的数据返回不同的内容类型,例如Excel文件 我使用了自定义媒体格式化程序来输出Excel数据,但是,我注意到,当我从客户端调用它时,没有安全性 在进行GET时,如果没有ACCEPT头,则会检查OAuth承载令牌,并接受或撤销访问。通过控制器上的[授权]设置授权 当我进行相同的GET时,ACCEPT头被设置为请求一个Excel文件,不管令牌是什么,都会调用控制器,从而绕过控制器上的安全性 很明显,我做错了什么,但我不知道会是什么。它是同一个控制器,但由于某些原因,当ACCEPT设置为受支持的媒体类型时,它始终允许访问 下面是我的设置的简化版本 Owin启动:C# 使用媒体格式化程序时在Web API中绕过的AuthorizeAttribute,c#,odata,asp.net-web-api2,C#,Odata,Asp.net Web Api2,我创建了一个web api应用程序,将ODataAPI公开给前端应用程序。这样做的原因之一是能够为相同的数据返回不同的内容类型,例如Excel文件 我使用了自定义媒体格式化程序来输出Excel数据,但是,我注意到,当我从客户端调用它时,没有安全性 在进行GET时,如果没有ACCEPT头,则会检查OAuth承载令牌,并接受或撤销访问。通过控制器上的[授权]设置授权 当我进行相同的GET时,ACCEPT头被设置为请求一个Excel文件,不管令牌是什么,都会调用控制器,从而绕过控制器上的安全性 很明显
[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.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;
}
}
}
名称空间Rest.Controllers
{
[授权]
公共类TestController:ApicController
{
私有dbSDSContext db=新的dbSDSContext();
//获取:api/测试
公共IQueryable GetTests()
{
返回db.test;
}
//获取:api/Test/5
[响应类型(类型(测试))]
公共异步任务GetTest(int-id)
{
test test=wait db.test.FindAsync(id);
if(test==null)
{
返回NotFound();
}
返回Ok(测试);
}
//PUT:api/Test/5
[响应类型(typeof(void))]
公共异步任务PutTest(int-id,test-test)
{
如果(!ModelState.IsValid)
{
返回请求(ModelState);
}
if(id!=test.testID)
{
返回请求();
}
db.Entry(test).State=EntityState.Modified;
尝试
{
等待db.saveChangesSync();
}
catch(DbUpdateConcurrencyException)
{
如果(!TestExists(id))
{
返回NotFound();
}
其他的
{
投掷;
}
}
返回状态码(HttpStatusCode.NoContent);
}
//职位:api/测试
[响应类型(类型(测试))]
公共异步任务后测试(测试)
{
如果(!ModelState.IsValid)
{
返回请求(ModelState);
}
db.test.Add(测试);
等待db.saveChangesSync();
返回CreatedAtRoute(“DefaultApi”,new{id=test.testID},test);
}
//删除:api/Test/5
[响应类型(类型(测试))]
公共异步任务DeleteTest(int-id)
{
test test=wait db.test.FindAsync(id);
if(test==null)
{
返回NotFound();
}
db.test.Remove(测试);
等待db.saveChangesSync();
返回Ok(测试);
}
受保护的覆盖无效处置(布尔处置)
{
如果(处置)
{
db.Dispose();
}
基地。处置(处置);
}
私有bool TestExists(int-id)
{
返回db.test.Count(e=>e.testID==id)>0;
}
}
}
该错误是由于在受影响的控制器中使用了错误的命名空间造成的
使用WebAPI时,请确保使用:
using System.Web.Http;
而不是:
using System.Web.Mvc;
奇怪。你能用一个完全简化的例子来证实吗?我已经添加了一个简化版本的代码。当将Accept标头设置为有效的内容类型(甚至是匿名用户)时,将调用控制器。发出应用程序/json请求时不会发生这种情况,它会正确地拒绝访问。然后,您是否可以在错误调用的方法中添加一行,以检查
上下文的值。User
?我想知道在请求的生命周期中设置了什么用户,所以绕过了授权。@WiktorZychla感谢您的输入。事实证明,我使用的是System.Web.Mvc.AuthorizeAttribute,而不是System.Web.Http.AuthorizeAttribute。很高兴您解决了这个问题,而且框架本身并不是一个巨大的安全漏洞。
using System.Web.Http;
using System.Web.Mvc;