2013-04-28 37 views
6

Tôi có API web C# consol tự lưu trữ. Nó phục vụ một số ứng dụng web sử dụng AngularJS để thực hiện các yêu cầu http không đồng bộ. Nó cần phải có cả hỗ trợ CORS và NTLM Authentication.Cách bật cả hỗ trợ CORS và xác thực NTLM

Tôi hiện đã bật cả hai, nhưng có vẻ như cách tôi đã triển khai khiến họ tự hủy. Tôi tin rằng điều này được thực hiện bởi phản hồi 401 ban đầu của tôi từ máy chủ. Điều này thường dẫn đến việc bắt tay xác thực giữa hai nhưng nhìn vào Fiddler, phản hồi 401 ban đầu này thiếu thẻ Access-Control-Allow-Origin, và điều này làm cho trình duyệt từ bỏ cái bắt tay. Tôi đã thực hiện một ứng dụng và cung cấp cho họ cùng một tên máy chủ để vô hiệu hóa sự cần thiết cho CORS, và cái bắt tay hoạt động hoàn hảo. Tôi đã tắt xác thực NTLM bằng cách thay thế NtlmSelfHostConfiguration tùy chỉnh của mình bằng HttpSelfHostConfiguration ban đầu và thẻ Access-Control-Allow-Origin thực thi hoàn hảo để cho phép CORS. chỉ khi cả hai hoạt động mà mọi thứ không hoạt động.

CẬP NHẬT: Tôi đã đặt một Breakpoint trong CorsHandle của mình theo yêu cầu không yêu cầu, chỉ để đảm bảo rằng máy chủ web có thể thực sự gọi nó trong khi sử dụng NtlmSelfHostConfiguration và nó đã thành công. Tôi chỉ muốn chắc chắn rằng không có gì trong NtlmSelfHostConfiguration mà thể chất ngăn chặn Corshandle từ bao giờ được gọi. Tất cả hoạt động tốt, Nó chắc chắn xuất hiện mà tôi cần phải tìm một cách để gọi CorsHandle ngay cả trên các yêu cầu mà không xác thực.

Đây là implimentation của tôi:

program.cs:

using System.Web.Http; 
using System.Web.Http.Validation.Providers; 
using System.Web.Http.SelfHost; 
namespace DCMAPI 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      string BaseAddress = "http://localhost:8080/"; 

      //NtlmSelfHostConfiguration is defined in HttpSelfHostConfiguration.cs 
      //it inherits from HttpSelfHostConfiguration 
      //and enables Ntlm Authentication. 

      var config = new NtlmSelfHostConfiguration(BaseAddress); 

      config.Routes.MapHttpRoute(
       "API Default", 
       "api/{controller}/{id}", 
       new { id = RouteParameter.Optional }); 

      //CorsHandler is also defined in CorsHandler.cs. It is what enables CORS 

      config.MessageHandlers.Add(new CorsHandler()); 

      var appXmlType = 
      config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault 
       (t => t.MediaType == "application/xml"); 
      config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);     

      config.Services.RemoveAll 
       (typeof(System.Web.Http.Validation.ModelValidatorProvider), 
       v => v is InvalidModelValidatorProvider); 

      using (HttpSelfHostServer server = new HttpSelfHostServer(config)) 
      { 
       server.OpenAsync().Wait(); 
       Console.WriteLine("running"); 
       Console.ReadLine(); 
      } 

     } 
    } 
} 

NtlmSelfHostConfiguration.cs

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Web.Http; 
using System.Web.Http.SelfHost; 
using System.Web.Http.SelfHost.Channels; 
using System.ServiceModel; 
using System.ServiceModel.Channels; 

namespace DCMAPI 
{ 
    public class NtlmSelfHostConfiguration : HttpSelfHostConfiguration 
    { 
     public NtlmSelfHostConfiguration(string baseAddress) 
      : base(baseAddress) 
     { } 

     public NtlmSelfHostConfiguration(Uri baseAddress) 
      : base(baseAddress) 
     { } 

     protected override BindingParameterCollection OnConfigureBinding 
      (HttpBinding httpBinding) 
     { 
      httpBinding.Security.Mode = 
       HttpBindingSecurityMode.TransportCredentialOnly; 

      httpBinding.Security.Transport.ClientCredentialType = 
       HttpClientCredentialType.Ntlm; 

      return base.OnConfigureBinding(httpBinding); 
     } 
    } 
} 

CorsHandle.cs

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Net.Http; 
using System.Threading.Tasks; 
using System.Threading; 
using System.Net; 

namespace DCMAPI 
{ 
    public class CorsHandler : DelegatingHandler 
    { 
     const string Origin = "Origin"; 
     const string AccessControlRequestMethod = "Access-Control-Request-Method"; 
     const string AccessControlRequestHeaders = "Access-Control-Request-Headers"; 
     const string AccessControlAllowOrigin = "Access-Control-Allow-Origin"; 
     const string AccessControlAllowMethods = "Access-Control-Allow-Methods"; 
     const string AccessControlAllowHeaders = "Access-Control-Allow-Headers"; 

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

      bool isCorsRequest = request.Headers.Contains(Origin); 
      bool isPreflightRequest = request.Method == HttpMethod.Options; 
      if (isCorsRequest) 
      { 

       if (isPreflightRequest) 
       { 
        HttpResponseMessage response = 
         new HttpResponseMessage(HttpStatusCode.OK); 

        response.Headers.Add(AccessControlAllowOrigin, 
         request.Headers.GetValues(Origin).First()); 

        string accessControlRequestMethod = 
         request.Headers.GetValues(AccessControlRequestMethod) 
         .FirstOrDefault(); 
        if (accessControlRequestMethod != null) 
        { 
         response.Headers.Add(
          AccessControlAllowMethods, accessControlRequestMethod); 
        } 

        string requestedHeaders = string.Join(", ", 
         request.Headers.GetValues(AccessControlRequestHeaders)); 
        if (!string.IsNullOrEmpty(requestedHeaders)) 
        { 
         response.Headers.Add(AccessControlAllowHeaders, 
          requestedHeaders); 
        } 

        TaskCompletionSource<HttpResponseMessage> tcs = 
         new TaskCompletionSource<HttpResponseMessage>(); 
        tcs.SetResult(response); 
        return tcs.Task; 
       } 
       else 
       { 
        return base.SendAsync(request, 
         cancellationToken).ContinueWith<HttpResponseMessage>(t => 
        { 
         HttpResponseMessage resp = t.Result; 
         resp.Headers.Add(
          AccessControlAllowOrigin, 
          request.Headers.GetValues(Origin).First()); 
         return resp; 
        }); 
       } 
      } 
      else 
      { 
       return base.SendAsync(request, cancellationToken); 
      } 
     } 
    } 
} 
+0

không thể bình luận về câu hỏi thực tế của bạn, nhưng để tạo một kết quả hoàn thành, bạn có thể chỉ cần sử dụng ['Task.FromResult '] (http://msdn.microsoft.com/en-us/library/hh194922.aspx) thay vì lộn xộn xung quanh với 'TaskCompletionSource ' – spender

+1

Bạn có thể muốn 'Access-Control-Allow-Credentials: true' trong tài nguyên CORS của bạn. Điều đó cho phép gửi cookie. –

+0

Câu trả lời sau đây có thể giúp: http://stackoverflow.com/a/15734032/107250 – monsur

Trả lời

8

Đây có thể là chút hơi muộn và Tôi không chắc chắn rằng nó sẽ giúp bạn, nhưng nó có thể giúp người khác tìm cách để có cả NTLM và CORS kích hoạt.

Tôi đang sử dụng Web API 2 cho API REST phụ trợ. Và AngularJS cho giao diện người dùng.

Trước hết, vì bạn đang sử dụng NTLM, số gọi XMLHttpRequest của bạn phải gửi thông tin đăng nhập. Trong AngularJs bạn làm như thế này:

$http.get(url, { withCredentials: true }); 

Sau đó, bạn phải kích hoạt CORS trên backend của bạn (trong WebApiConfig.Register()):

 var enableCorsAttribute = new EnableCorsAttribute("*", "*", "*") 
      { 
       SupportsCredentials = true 
      }; 
     config.EnableCors(enableCorsAttribute); 

SupportsCredentials = true nghĩa là chúng ta sẽ thêm Access-Control-Allow-Credentials để phản ứng.

Các ký tự đại diện có nghĩa là chúng ta cho phép:

  • CORS từ bất kỳ nguồn gốc
  • Tất cả các yêu cầu tiêu đề
  • Bất kỳ HTTP Động từ (phương pháp)
+0

cảm ơn nó thực sự đã giúp tôi ... –

Các vấn đề liên quan