WebApi
WebApi copied to clipboard
OData batch with authentication
Based on http://odata.github.io/WebApi/04-12-batch/ and https://github.com/OData/ODataSamples/tree/master/WebApiCore/ODataBatchSample I was able to implement batching. However as soon as I add authentication the batching fails. It doesn't even hit my controller.
Authentication is implemented with JWT Bearer.
This is the body of my POST request to localhost/odata/$batch:
--batch_d3bcb804-ee77-4921-9a45-761f98d32029
Content-Type: application/http
Content-Transfer-Encoding: binary
GET http://localhost:54866/odata/Customers HTTP/1.1
OData-Version: 4.0
OData-MaxVersion: 4.0
Accept: application/json;odata.metadata=minimal
Accept-Charset: UTF-8
User-Agent: Microsoft ADO.NET Data Services
--batch_d3bcb804-ee77-4921-9a45-761f98d32029
Content-Type: application/http
Content-Transfer-Encoding: binary
GET http://localhost:54866/odata/Orders HTTP/1.1
OData-Version: 4.0
OData-MaxVersion: 4.0
Accept: application/json;odata.metadata=minimal
Accept-Charset: UTF-8
User-Agent: Microsoft ADO.NET Data Services
--batch_d3bcb804-ee77-4921-9a45-761f98d32029--
This is the response when authentication is disabled:
--batchresponse_5c899c88-2dc9-489e-aaf3-c3a14308a2ae
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 200 OK
Content-Type: application/json; odata.metadata=minimal; odata.streaming=true; charset=utf-8
OData-Version: 4.0
{"@odata.context":"http://localhost:54866/odata/$metadata#Customers","value":[{...}]}
--batchresponse_5c899c88-2dc9-489e-aaf3-c3a14308a2ae
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 200 OK
Content-Type: application/json; odata.metadata=minimal; odata.streaming=true; charset=utf-8
OData-Version: 4.0
{"@odata.context":"http://localhost:54866/odata/$metadata#Orders","value":[{...}]}
--batchresponse_5c899c88-2dc9-489e-aaf3-c3a14308a2ae--
This is the response when authentication is enabled:
--batchresponse_8f51fb60-5158-4d1a-a492-87a561220374
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 200 OK
--batchresponse_8f51fb60-5158-4d1a-a492-87a561220374
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 200 OK
--batchresponse_8f51fb60-5158-4d1a-a492-87a561220374--
Is it possible to implement batching with JWT Bearer authentication enabled?
Have you got your middleware in the right order? Authentication should come before adding the odata batching middleware I believe
@freeranger It must have indeed been something with the order of the middlewares. Either that or I was passing a bad JWT token, which leads me to this.
It works when I am using a valid JWT token at the moment. However, I am still getting 200 OK when I am not authenticated. I would expect a 401 instead. Any reason why this is not the case?
--batchresponse_8f51fb60-5158-4d1a-a492-87a561220374
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 200 OK
--batchresponse_8f51fb60-5158-4d1a-a492-87a561220374
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 200 OK
--batchresponse_8f51fb60-5158-4d1a-a492-87a561220374--
'ello
I know this is an old thread, but I have the same question.
I'm using OData 8.0.10 & .net 6. My application uses windows authentication, but also allows for some anoymous calls.
Services are added in the following order
services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();
services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});
services
.AddControllers()
.AddOData(opt =>
opt.AddRouteComponents("OData", model, new DefaultODataBatchHandler())
.Select()
.Filter()
.OrderBy()
.Count()
.Expand()
.SetMaxTop(null));
Posting the following to my Batch EndPoint using Postman & no Authentication
--changeset_3ca6628a-1f84-4772-bbe4-02192ed229f4
Content-Type: application/http
Content-Transfer-Encoding: binary
PUT /OData/CompanyInfo('6008079') HTTP/1.1
Accept: application/json, text/javascript, */*; q=0.01
Content-Id: 0
Content-Type: application/json; charset=utf-8
Content-Length: 75
{"GS1CompanyPrefix":"6008079","Description":"Namib Mills","Prefix":"NM"}
--changeset_3ca6628a-1f84-4772-bbe4-02192ed229f4--
returns
--batchresponse_a137b646-3272-4866-baaf-8c6b98667509
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 200 OK
--batchresponse_a137b646-3272-4866-baaf-8c6b98667509--
The PUT request silently fails, so te update does not apply, but one would expect a 401...
Any light on this subject will be appreciated.
Regards
Hi @HeinA , did you resolve this? I've noticed that with OData 8.0.11 & .NET 6.0 the batch looses the Identity from the HttpContext. We're using a custom batch handler and can clearly see that this is empty.
Hi , im using net 7 and Odata v8.0.11 and when i use the bath the services variables (IHttpContextAccessor acessor) its come null .
services.AddControllers().AddOData(opt =>
opt.AddRouteComponents("Odata", GetEdmModel() , new DefaultODataBatchHandler()).Select().Filter().OrderBy().Expand().Count().SetMaxTop(null)
);
app.UseODataBatching(); app.UseCors(x => x.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader()); app.UseHttpsRedirection(); app.UseAuthentication(); app.MapControllers(); app.UseAuthorization();
@garrardkitchen , @DanielRBG I never got a fix for my specific issue, but I can help you with the null IHttpContextAccessor...
Create a Middleware Callback Type:
using log4net;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
namespace Nmi.Application.Server.MiddleWare
{
internal class ODataBatchHttpContextMiddleware
{
private readonly RequestDelegate _next;
private readonly IHttpContextAccessor _httpAccessor;
private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public ODataBatchHttpContextMiddleware(RequestDelegate next, IHttpContextAccessor httpAccessor)
{
_next = next;
_httpAccessor = httpAccessor;
}
public async Task InvokeAsync(HttpContext context)
{
if (context is null) log.Error("Cannot set HttpContext");
_httpAccessor.HttpContext ??= context;
await _next(context);
}
}
}
Add it in the following sequence:
app.UseAuthentication(); // (Not in recomended order)
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseODataBatching(); // Must be before UseRouting(), Must be after UseAuthentication()
app.UseRouting();
app.UseAuthorization();
// Custom Middleware goes here
app.UseMiddleware<ODataBatchHttpContextMiddleware>(); // Must be after UseODataBatching()
app.UseEndpoints(endpoints =>...);
@garrardkitchen , @DanielRBG I never got a fix for my specific issue, but I can help you with the null IHttpContextAccessor...
Create a Middleware Callback Type:
using log4net; using Microsoft.AspNetCore.Http; using System.Threading.Tasks; namespace Nmi.Application.Server.MiddleWare { internal class ODataBatchHttpContextMiddleware { private readonly RequestDelegate _next; private readonly IHttpContextAccessor _httpAccessor; private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); public ODataBatchHttpContextMiddleware(RequestDelegate next, IHttpContextAccessor httpAccessor) { _next = next; _httpAccessor = httpAccessor; } public async Task InvokeAsync(HttpContext context) { if (context is null) log.Error("Cannot set HttpContext"); _httpAccessor.HttpContext ??= context; await _next(context); } } }Add it in the following sequence:
app.UseAuthentication(); // (Not in recomended order) app.UseBlazorFrameworkFiles(); app.UseStaticFiles(); app.UseODataBatching(); // Must be before UseRouting(), Must be after UseAuthentication() app.UseRouting(); app.UseAuthorization(); // Custom Middleware goes here app.UseMiddleware<ODataBatchHttpContextMiddleware>(); // Must be after UseODataBatching() app.UseEndpoints(endpoints =>...);
Cheers this solved it for me