2011-08-18 29 views
8

Tôi chỉ đang học ASP.NET MVC và gần đây tôi đã tìm thấy thuộc tính [RequireHttps] để tự động chuyển hướng yêu cầu GET để sử dụng SSL, như vậy ...Cách chỉ định một cổng khác với thuộc tính RequireHttps trong MVC3

[RequireHttps] //apply to all actions in controller 
public class SomeController 
{ 
    [RequireHttps] //apply to this action only 
    public ActionResult SomeAction() 
    { 
     ... 
    } 
} 

Khi sử dụng IIS Express làm máy chủ phát triển, điều này chuyển hướng thành công yêu cầu từ http://localhost:55945/... đến https://localhost/.... Tuy nhiên, trên hệ thống phát triển của tôi, dự án của tôi đang sử dụng HTTPS trên cổng 44300 (được cấu hình tự động bởi Visual Studio 2010), và tôi chưa tìm được cách nào để nói MVC sử dụng số cổng đó trong chuyển hướng, vì vậy thay vào đó, nó được chuyển đến yêu cầu https://localhost:43300/.... Tôi thực sự mong đợi điều này là tự động, do số cổng SSL được thiết lập tự động bởi Visual Studio, và theo như tôi có thể nói, điều này phải có hiệu lực cho tất cả các nhà phát triển bằng cách sử dụng thuộc tính [RequireHttps] trong MVC3. Trong tìm kiếm của tôi cho một giải pháp, tôi đã nhìn thấy một vài giải pháp "làm việc xung quanh" chắp vá, nhưng không có gì mà dường như chắc chắn "đúng cách" để sửa chữa nó.

Vì vậy, làm những điều "đúng cách", tôi phải thay đổi gì (trong mã nguồn hoặc trong cấu hình dự án) để nói thuộc tính [RequireHttps] trong MVC3 để sử dụng cổng HTTPS mà dự án của tôi được định cấu hình đang sử dụng?

Hoặc cách khác, có cách nào khác hoàn toàn khác và tốt hơn "đúng cách" để thiết lập hỗ trợ SSL trong dự án MVC3, không có vấn đề này?

Trả lời

12

Yêu cầuHttpsAttribute khá đơn giản và không thể được parametrized chuyển hướng đến một cổng cụ thể. Nếu bạn thực sự cần điều này, bạn có thể tạo một lớp con và ghi đè phương thức HandleNonHttpsRequest để soạn url chuyển hướng khác nhau.

protected override void HandleNonHttpsRequest(AuthorizationContext filterContext) { 
    base.HandleNonHttpsRequest(filterContext); 

    // redirect to HTTPS version of page 
    string url = "https://" + filterContext.HttpContext.Request.Url.Host + ":" + MyConfig.SslPort + filterContext.HttpContext.Request.RawUrl; 
    filterContext.Result = new RedirectResult(url); 
} 

Tuy nhiên, nếu toàn bộ trang web của bạn chạy với HTTPS bạn chỉ có thể cấu hình trong VS trong các thuộc tính dự án web (Web -> Bắt đầu hành động -> URL Bắt đầu) để mở url HTTPS đúng với cổng của bạn và không sử dụng tính năng chuyển hướng để thử nghiệm cục bộ.

+0

Tôi nhận được phần đầu tiên của câu trả lời của bạn, mặc dù nó có vẻ giống như một hack, cho một cái gì đó mà không cần phải bị tấn công. Nhưng tôi không hiểu đoạn cuối của bạn. Tôi cần hệ thống phát triển của tôi để hành xử (chặt chẽ như thực tế) theo cùng một cách mà hệ thống người dùng sẽ hành xử. Điều đó có nghĩa là một số trang sẽ sử dụng HTTPS và một số trang sẽ không sử dụng. Điều đó cũng có nghĩa là tôi không thể kiểm soát URL mà người dùng sẽ nhập vào trang web. –

+0

Điều tôi muốn nói là bạn có thể không cần chuyển hướng thực sự để làm việc trên máy tính của bạn, và trong quá trình sản xuất, nó sẽ là cổng HTTPS chuẩn. Đây sẽ là trường hợp nếu toàn bộ trang web chạy dưới HTTPS, vì bạn chỉ có thể khởi động ứng dụng bằng cổng HTTPS phù hợp và ở trong ngữ cảnh HTTPS. Nếu tôi hiểu rõ thì đây không phải là trường hợp, vì vậy bạn cần phải thực hiện chuyển hướng trên máy tính của bạn. Tôi cập nhật câu trả lời và cố gắng để cụm từ tốt hơn những gì tôi có nghĩa là, nhưng nó có thể không có liên quan cho bạn anyway. –

2

Một vài điều có thể hữu ích.

Có một phiên bản mã nguồn RequireHttpsAttribute trong luồng này: Where is the source for RequireHttpsAttribute?

Ngoài ra còn có một lớp học gần giống gọi RequireSslAttribute trên CodePlex nêu trên cùng một sợi. http://aspnet.codeplex.com/SourceControl/changeset/view/63930#391756

Đây là mẫu thuộc tính có thể được sử dụng để chuyển đổi từ http sang https hoặc ngược lại dựa trên thuộc tính TargetUriScheme. Nó cũng bao gồm các thuộc tính để xác định số cổng.

Tôi đã chọn sử dụng khối # DE DEBUG trong hàm dựng của mình để đặt các cổng phát triển cục bộ khi tôi xây dựng theo cấu hình Gỡ lỗi.Điều này làm việc cho tôi vì tôi luôn xây dựng theo bản phát hành khi triển khai, trong trường hợp đó số cổng sẽ mặc định là null và sẽ bị loại bỏ khỏi url.

Số cổng cũng có thể được đặt khi áp dụng thuộc tính cho phương thức hành động. Tôi cũng có thể thấy hooking chúng vào một tập tin cấu hình hoặc một số nguồn cấu hình khác để xác định số cổng khi chạy.

public class ToggleHttpHttpsAttribute : FilterAttribute, IAuthorizationFilter 
{ 
    //supported uri scheme values 
    public enum UriScheme 
    { 
     Http, 
     Https 
    } 

    public ToggleHttpHttpsAttribute(
     UriScheme uriScheme = UriScheme.Http) 
    { 
     TargetUriScheme = uriScheme; 
    #if DEBUG 
     //set DEBUG ports 
     HttpPort = 55892; 
     HttpsPort = 44301; 
    #endif 
    } 

    private UriScheme TargetUriScheme { get; set; } 
    public int? HttpPort { get; set; } 
    public int? HttpsPort { get; set; } 

    public void OnAuthorization(AuthorizationContext filterContext) 
    { 
     if(filterContext == null) 
     { 
      throw new ArgumentNullException("filterContext"); 
     } 

     bool isHttps = filterContext.HttpContext.Request.IsSecureConnection; 

     if ((isHttps && TargetUriScheme == UriScheme.Http) || (!isHttps && TargetUriScheme == UriScheme.Https)) 
     { 
      ToggleUriScheme(filterContext); 
     } 
    } 

    private void ToggleUriScheme(AuthorizationContext filterContext) 
    { 
     //only allow toggle if GET request 
     if (!string.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) 
     { 
      throw new InvalidOperationException("ToggleHttpHttpsAttribute can only be used on GET requests."); 
     } 

     filterContext.Result = GetRedirectResult(filterContext); 
    } 

    private RedirectResult GetRedirectResult(AuthorizationContext filterContext) 
    { 
     string prefix = TargetUriScheme == UriScheme.Http 
      ? "http://" 
      : "https://"; 

     int? port = TargetUriScheme == UriScheme.Http 
      ? HttpPort 
      : HttpsPort; 

     string url = string.Format(
      "{0}{1}{2}{3}", 
      prefix, 
      filterContext.HttpContext.Request.Url.Host, 
      port == null ? "" : string.Format(":{0}", port), 
      filterContext.HttpContext.Request.RawUrl); 

     return new RedirectResult(url); 
    } 
} 
2

Tôi có vấn đề này giống nhau, và tôi giải quyết nó bằng cách sử dụng cả hai nguyên tắc RequireHttpsAttribute và viết lại URL trong Web.config. Quy tắc ghi lại khớp với các số cổng không chuẩn, và thực thi trước thuộc tính. Bạn có thể sử dụng một biến đổi Web.config để loại bỏ quy tắc viết lại khi triển khai, nhưng nếu bạn để nó trong nó sẽ không có bất kỳ hiệu ứng nào. Trong quá trình sản xuất, bạn sẽ sử dụng số cổng tiêu chuẩn mà quy tắc sẽ không khớp. Sau đó, thuộc tính sẽ bắt được nó.

Dưới đây là các quy tắc:

<system.webServer> 
    <rewrite> 
    <rules> 
    <!-- Redirect HTTP requests to HTTPS, using the non-standard development ports. 
    On deployment, this rule is removed, and the RequireHttpAttribute filter globally applied 
    in SlicerWeb.FilterConfig takes over. This rewrite rule executes before the attribute 
    would be applied, and so can apply the port numbers --> 
     <rule name="HTTPS redirect" stopProcessing="true"> 
     <match url="(.*)" /> 
     <conditions> 
      <add input="{HTTPS}" pattern="off" ignoreCase="true" /> 
      <add input="{SERVER_PORT}" pattern="60470" /> 
     </conditions> 
     <action type="Redirect" url="https://{SERVER_NAME}:44300/{R:1}" redirectType="Found" /> 
     </rule> 
    </rules> 
    </rewrite> 
</system.webServer> 

Nhược điểm để phương pháp này là bạn không dựa vào các thuộc tính khi chạy cục bộ. Nhưng nếu bạn đã áp dụng nó một lần trên toàn cầu, thay vì thêm nó vào mọi bộ điều khiển, đó là OK theo ý kiến ​​của tôi.

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