2

基本認証を使用したクロス ドメイン アクセスを許可する Web API をセットアップしました。API に対してクロス ドメイン GET 要求を行うと、正常に動作し、カスタム メッセージ ハンドラーの "Authorization" ヘッダーでトークンを取得しています。しかし、クロスドメイン POST リクエストを開始するときに、「Authorization」ヘッダーを取得していないため、リクエストを検証できません。

どんな助けでも大歓迎です。

以下は、クロス ドメイン アクセス用のカスタム メッセージ ハンドラーのコードです。

    using System;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Threading;
    using System.Threading.Tasks;

    namespace MyWebApi.Handlers
    {
        public class XHttpMethodOverrideDelegatingHandler : DelegatingHandler
        {
            static readonly string[] HttpOverrideMethods = { "PUT", "DELETE" };
            static readonly string[] AccessControlAllowMethods = { "POST", "PUT", "DELETE" };
            private const string HttpMethodOverrideHeader = "X-HTTP-Method-Override";
            private const string OriginHeader = "ORIGIN";
            private const string AccessControlAllowOriginHeader = "Access-Control-Allow-Origin";
            private const string AccessControlAllowMethodsHeader = "Access-Control-Allow-Methods";
            private const string AccessControlAllowHeadersHeader = "Access-Control-Allow-Headers";

            protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
            {


                 var authHeader = request.Headers.Authorization;

                if (authHeader == null || authHeader.Scheme != "Basic" || string.IsNullOrWhiteSpace(authHeader.Parameter))
                {
                    return CreateUnauthorizedResponse();
                }

                if (request.Method == HttpMethod.Post && request.Headers.Contains(HttpMethodOverrideHeader))
                {
                    var httpMethod = request.Headers.GetValues(HttpMethodOverrideHeader).FirstOrDefault();
                    if (HttpOverrideMethods.Contains(httpMethod, StringComparer.InvariantCultureIgnoreCase))
                        request.Method = new HttpMethod(httpMethod);
                }

                var httpResponseMessage = base.SendAsync(request, cancellationToken);

                if (request.Method == HttpMethod.Options && request.Headers.Contains(OriginHeader))
                {
                    httpResponseMessage.Result.Headers.Add(AccessControlAllowOriginHeader, request.Headers.GetValues(OriginHeader).FirstOrDefault());
                    httpResponseMessage.Result.Headers.Add(AccessControlAllowMethodsHeader, String.Join(", ", AccessControlAllowMethods));
                    httpResponseMessage.Result.Headers.Add(AccessControlAllowHeadersHeader, HttpMethodOverrideHeader);
                    httpResponseMessage.Result.StatusCode = HttpStatusCode.OK;
                }
                //No mater what the HttpMethod (POST, PUT, DELETE), if a Origin Header exists, we need to take care of it
                else if (request.Headers.Contains(OriginHeader))
                {
                    httpResponseMessage.Result.Headers.Add(AccessControlAllowOriginHeader, request.Headers.GetValues(OriginHeader).FirstOrDefault());
                }

                return httpResponseMessage;
            }

            private Task<HttpResponseMessage> CreateUnauthorizedResponse()
            {
                var response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
                response.Headers.Add("WWW-Authenticate", "Basic");

                var taskCompletionSource = new TaskCompletionSource<HttpResponseMessage>();
                taskCompletionSource.SetResult(response);
                return taskCompletionSource.Task;
            }
        }
    }

そして、次のように Application_Start に上記のハンドラーを登録しました。

    namespace MyWebApi
    {
        public class Global : System.Web.HttpApplication
        {
            protected void Application_Start(object sender, EventArgs e)
            {
                RouteTable.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{action}/{id}",
                    defaults: new {id = RouteParameter.Optional});
                GlobalConfiguration.Configuration.MessageHandlers.Add(new XHttpMethodOverrideDelegatingHandler()); 
                GlobalConfiguration.Configuration.Formatters.Insert(0, new JsonpMediaTypeFormatter());
            }
        }
    }

別のドメイン プロジェクトのクライアント側で、次のコードを使用して新しいレコードを追加しようとしています。

     AddUser {

                var jsonData = {
                    "FirstName":"My First Name",
                    "LastName": "My Last Name",
                    "Email": "my.name@mydomain.com",
                    "Password": "MyPa$$word"
                };

                $.ajax({
                    type: "POST",
                    dataType: 'json',
                    url: "http://localhost:4655/api/user/signup",
                    beforeSend: function (xhr) { xhr.setRequestHeader("Authorization", "Basic xxxxxxxxxxxxxx"); },
                    accept: "application/json",
                    data: JSON.stringify(jsonData),
                    success: function (data) {
                        alert("success");
                    },
                    failure: function (errorMsg) {
                        alert(errorMsg);

                    },
                    error: function (onErrorMsg) {
                        alert(onErrorMsg.statusText);
                    },
                    statusCode: function (test) {
                        alert("status");
                    }
                });
            });

以下は、私のユーザーコントローラーのコードです。

    namespace MyWebApi.Controllers
    {
        public class UserController : ApiController
        {

            [HttpPost]
            [ActionName("Adduser")]
            public int Post(UserModel source)
            {
                    if (source == null)
                    {
                        throw new ArgumentNullException("source");
                    }
                    Db.Users.Add(source);
                    Db.SaveChanges();

                    return source.UserId;
            }                
        }
    }

前もって感謝します!

4

2 に答える 2

0

クロスドメイン (POST) XHR リクエストに基本的な認証資格情報を含めると、サーバーに到達する前にブラウザー (IE、Chrome、Firefox) がリクエストを拒否することを発見しました。withCredentials:true私の最初の $.ajax() リクエストで。これを必要とするCORS仕様におそらく何かがあると思います。しかし、短い答えは、CORS リクエストで基本認証を指定できないということだと思います。

もちろん、ユーザー ID とパスワードを適切な URL の一部として渡すことで、これを回避することもできます。そのため、ユーザー ID とパスワードを制限することで何を得ていると彼らが考えているかは完全にはわかりませんが、おそらく何らかの理由があると思われます。

于 2013-09-25T16:52:56.870 に答える
0

[HttpOptions] と [HttpPost] でコントローラーをデコレートする必要があります。それ以外の場合、OPTIONS動詞を使用してリクエストを行うと、404がスローされます。したがって、コントローラーは

        [HttpPost]
        [HttpOptions]
        [ActionName("Adduser")]
        public int Post(UserModel source)
        {
                if (source == null)
                {
                    throw new ArgumentNullException("source");
                }
                Db.Users.Add(source);
                Db.SaveChanges();

                return source.UserId;
        }
于 2013-10-18T08:55:06.090 に答える