OData V4批处理请求基本授权

Jam*_*ack 5 c# authorization odata owin

我们的OData端点是自托管的(OWIN)。对于单个请求:创建,更新,修补和删除所有内容都很好,但是问题是当我发送包含多个操作的批处理请求时,基本授权出现了问题。我读了很多文章,但仍然无法解决问题。在OData文档中说:

代表单个请求的每个MIME部件正文都不得包含:

• authentication or authorization related HTTP headers
Run Code Online (Sandbox Code Playgroud)

http://docs.oasis-open.org/odata/odata/v4.0/errata03/os/complete/part1-protocol/odata-v4.0-errata03-os-part1-protocol-complete.html#_Toc453752314

因此,如果我将Authorization设置为批处理请求,但未将其设置为批处理中的每个请求,那么OnAuthorization方法中的actionContext.Request.Headers.Authorization会为null。我的问题是:如何从该批次中的请求获取批次请求的授权标头?

在端点中启用了“批次”:

HttpConfiguration config = new HttpConfiguration();
var odataBatchHandler = new DefaultODataBatchHandler(new HttpServer(config));
config.MapODataServiceRoute("ODataApi", null, builder.GetEdmModel(), odataBatchHandler);
config.Count().Filter().OrderBy().Expand().MaxTop(null).Select();
appBuilder.UseWebApi(config);
Run Code Online (Sandbox Code Playgroud)

这是授权逻辑:

public class ODataBasicAuthorizeAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
         //Question: here Authorization property is null, because this is Get request for SAStudent
                if (actionContext.Request.Headers.Authorization == null || actionContext.Request.Headers.Authorization.Scheme != "Basic")
                {
                    HandleUnauthorizedRequest(actionContext);
                }
                else
                {
                    ISession session = Login(actionContext.Request);
                    if (session == null)
                    {
                        HandleUnauthorizedRequest(actionContext);
                    }
                    else
                    {
                        IsAuthorized(actionContext);
                    }
                }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是测试:

    [TestMethod]
        public void BatchRequestTest()
        {
            var odataAddress = "https://localhost:23170/Sample/Sample/OData/";
            var batchUrl = $"{odataAddress}$batch";
            HttpClient http = new HttpClient();
            // Global batch request
            HttpRequestMessage batchRequest = new HttpRequestMessage(HttpMethod.Post, batchUrl);
            batchRequest.Headers.Authorization = new AuthenticationHeaderValue("Basic", "QWRtaW5pc3RyYXRvcjpwdw==");
            MultipartContent batchContent = new MultipartContent("mixed", "batch_" + Guid.NewGuid().ToString());

            var getStudent = new HttpRequestMessage(HttpMethod.Get, $"{odataAddress}SAStudent");
            //getStudent.Headers.Authorization = new AuthenticationHeaderValue("Basic", "QWRtaW5pc3RyYXRvcjpwdw==");
            // First message content with GET request
            HttpMessageContent getRequestContent_1 = new HttpMessageContent(getStudent);
            getRequestContent_1.Headers.Remove("Content-Type");
            getRequestContent_1.Headers.Add("Content-Type", "application/http");
            getRequestContent_1.Headers.Add("Content-Transfer-Encoding", "binary");
            // Add this GET content to the batch content
            batchContent.Add(getRequestContent_1);

            var getPassport = new HttpRequestMessage(HttpMethod.Get, $"{odataAddress}SAPassport");
            //getPassport.Headers.Authorization = new AuthenticationHeaderValue("Basic", "QWRtaW5pc3RyYXRvcjpwdw==");
            // Second message content with GET request
            HttpMessageContent getRequestContent_2 = new HttpMessageContent(getPassport);
            getRequestContent_2.Headers.Remove("Content-Type");
            getRequestContent_2.Headers.Add("Content-Type", "application/http");
            getRequestContent_2.Headers.Add("Content-Transfer-Encoding", "binary");
            // Add this GET content to the batch content
            batchContent.Add(getRequestContent_2);

            // Here we go
            batchRequest.Content = batchContent;
            HttpResponseMessage response = http.SendAsync(batchRequest).Result;
            var responseString = response.Content.ReadAsStringAsync().Result;

}
Run Code Online (Sandbox Code Playgroud)

如果我将批处理请求中的每个请求都设置为授权,那么它将起作用,但是似乎不正确,因此仅将授权标头设置为批处理应该起作用。

有任何想法吗?

提前致谢,

mou*_*nds 0

聚会迟到了,但最近遇到了类似的问题,尽管是使用 Http Cookie 进行自定义身份验证。

首先,确保 Web Api 和 Batch Handler 配置为使用同一 HttpServer 实例。

HttpConfiguration config = new HttpConfiguration();
HttpServer httpServer = new HttpServer(config);
var odataBatchHandler = new DefaultODataBatchHandler(httpServer);
config.MapODataServiceRoute("ODataApi", null, builder.GetEdmModel(), odataBatchHandler);
config.Count().Filter().OrderBy().Expand().MaxTop(null).Select();
appBuilder.UseWebApi(httpServer);
Run Code Online (Sandbox Code Playgroud)

我发现如果没有这个,封闭的 $batch 请求中的任何上下文都无法供每个子请求使用,因为 odata 批处理处理程序正在使用与 Web api 不同的 HttpServer 实例。

我现在可以从 OwinContext 中获取标头以进行自定义身份验证 - 在您的情况下......

public class ODataBasicAuthorizeAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        //Question: here Authorization property is null, because this is Get request for SAStudent

        var isBatch = request.Properties.TryGetValue("MS_BatchRequest", out var value) ? (bool)value : default;
        OwinContext owinContext = request.Properties.TryGetValue("MS_OwinContext", out var owinCtxObj) ? (OwinContext)owinCtxObj : default;
        if (isBatch && owinContext != null)
        {
            // adjust your auth logic to use the owin context... my case I needed a cookie, so...
            // var jwtCookieKeyValuePair = owinContext.Request.Cookies.FirstOrDefault(cookie => cookie.Key == "jwt");
        }
        // Keep your existing logic for non-batch odata requests..
        if (actionContext.Request.Headers.Authorization == null || actionContext.Request.Headers.Authorization.Scheme != "Basic")
        {
            HandleUnauthorizedRequest(actionContext);
        }
        else
        {
            ISession session = Login(actionContext.Request);
            if (session == null)
            {
                HandleUnauthorizedRequest(actionContext);
            }
            else
            {
                IsAuthorized(actionContext);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

对于OP来说,一切可能都太晚了,但可能会对某人有所帮助。