2010-09-02 34 views
25

Tôi muốn trang đăng nhập của tôi là chỉ SSL:ASP.NET MVC: Cách tự động tắt [RequireHttps] trên localhost?

[RequireHttps] 
    public ActionResult Login() 
    { 
     if (Helper.LoggedIn) 
     { 
      Response.Redirect("/account/stats"); 
     } 

     return View(); 
    } 

Nhưng rõ ràng là nó không hoạt động trên localhost khi tôi phát triển và gỡ lỗi ứng dụng của tôi. Tôi không muốn sử dụng IIS 7 với chứng chỉ SSL, làm thế nào tôi có thể tự động vô hiệu hóa thuộc tính RequireHttps?

Cập nhật

Dựa trên thông tin được cung cấp bởi người dùng StackOverflow và ASP.NET MVC 2 mã nguồn Tôi tạo ra lớp sau đó giải quyết vấn đề.

public class RequireSSLAttribute : FilterAttribute, IAuthorizationFilter 
{ 
    public virtual void OnAuthorization(AuthorizationContext filterContext) 
    { 
     if (filterContext == null) 
     { 
      throw new ArgumentNullException("filterContext"); 
     } 

     if (!filterContext.HttpContext.Request.IsSecureConnection) 
     { 
      HandleNonHttpsRequest(filterContext); 
     } 
    } 

    protected virtual void HandleNonHttpsRequest(AuthorizationContext filterContext) 
    { 
     if (filterContext.HttpContext.Request.Url.Host.Contains("localhost")) return; 

     if (!String.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) 
     { 
      throw new InvalidOperationException("The requested resource can only be accessed via SSL"); 
     } 

     string url = "https://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl; 
     filterContext.Result = new RedirectResult(url); 
    } 
} 

Và nó được sử dụng như thế này:

[RequireSSL] 
public ActionResult Login() 
{ 
    if (Helper.LoggedIn) 
    { 
     Response.Redirect("/account/stats"); 
    } 

    return View(); 
} 
+0

Nếu bạn tìm kiếm Stack Overflow cho "RequireHttps" câu hỏi đã được hỏi một vài lần, vì vậy rất nhiều thông tin liên quan đến giải pháp. Tuy nhiên, đó là một câu hỏi hay, tôi chưa sử dụng thuộc tính đó nhưng tôi có thể thấy đó là một vấn đề ngay lập tức. –

+0

Bạn nói đúng. Vấn đề đã được giải quyết và tôi đã cập nhật bài đăng chính của mình với lớp học đã giúp tôi. – Alex

Trả lời

25

Điều đơn giản nhất sẽ được lấy một thuộc tính mới từ RequireHttps và ghi đè HandleNonHttpsRequest

protected override void HandleNonHttpsRequest(AuthorizationContext filterContext) 
     { 
      if (!filterContext.HttpContext.Request.Url.Host.Contains("localhost")) 
      { 
       base.HandleNonHttpsRequest(filterContext); 
      } 
     } 

HandleNonHttpsRequest là phương pháp mà ném ngoại lệ, ở đây tất cả chúng tôi đang làm là không gọi nó nếu máy chủ lưu trữ là localhost (và như Jeff nói trong bình luận của anh ta, bạn có thể mở rộng điều này để kiểm tra môi trường hoặc trên thực tế bất kỳ ngoại lệ nào khác mà bạn muốn).

+0

Phương pháp này có thể được sửa đổi cũng không yêu cầu HTTPS trong môi trường thử nghiệm. –

+0

Tôi nên đặt mã này ở đâu? Cập nhật Tôi không bao giờ để ý đến điều này. – Alex

+0

Tôi đã sử dụng mã nguồn và mã nguồn của MVC để tạo giải pháp. Cảm ơn! – Alex

14
#if (!DEBUG) 
[RequireHttps] 
#endif 
public ActionResult Login() 
{ 
    if (Helper.LoggedIn) 
    { 
     Response.Redirect("/account/stats"); 
    } 

    return View(); 
} 
+2

Tôi cũng nghĩ về điều này. Nhưng nó có nghĩa là tôi phải thêm # DEBUG cho mỗi thuộc tính RequireHttps. – Alex

+0

à, tôi nghĩ đó chỉ là một lần duy nhất. Các đề xuất khác là tốt hơn sau đó. – Femaref

8

Bạn có thể đóng gói yêu cầu này trong một thuộc tính có nguồn gốc:

class RequireHttpsNonDebugAttribute : RequireHttpsAttribute { 
    public override void HandleNonHttpsRequest(AuthorizationContext ctx) { 
     #if (!DEBUG) 
     base.HandleNonHttpsRequest(ctx); 
     #endif 
    } 
} 
17
public static void RegisterGlobalFilters(GlobalFilterCollection filters) { 

     if (!HttpContext.Current.IsDebuggingEnabled) { 
      filters.Add(new RequireHttpsAttribute()); 
     } 
    } 
+0

Sẽ hữu ích hơn khi thêm một chút thông tin về vị trí đặt mã này, chỉ để giúp những người không quen với ASP.NET MVC. – Andrew

+4

Trong dự án MVC hiện tại của tôi, có một tệp mặc định trong thư mục App_Start có tên là FilterConfig.cs. Thêm nó ở đó. – fabspro

1

MVC 6 (ASP.NET Lõi 1.0):

Các giải pháp thích hợp sẽ được sử dụng env.IsProduction() hoặc env.IsDevelopment().

Ví dụ:

Startup.cs - AddMvc với một bộ lọc tùy chỉnh:

public void ConfigureServices(IServiceCollection services) 
{ 
    // TODO: Register other services 

    services.AddMvc(options => 
    { 
     options.Filters.Add(typeof(RequireHttpsInProductionAttribute)); 
    }); 
} 

Tuỳ chỉnh bộ lọc kế thừa từ các quyết định RequireHttpsAttribute

public class RequireHttpsInProductionAttribute : RequireHttpsAttribute 
{ 
    private bool IsProduction { get; } 

    public RequireHttpsInProductionAttribute(IHostingEnvironment environment) 
    { 
     if (environment == null) 
      throw new ArgumentNullException(nameof(environment)); 
     this.IsProduction = environment.IsProduction(); 
    } 
    public override void OnAuthorization(AuthorizationContext filterContext) 
    { 
     if (this.IsProduction) 
      base.OnAuthorization(filterContext); 
    } 
    protected override void HandleNonHttpsRequest(AuthorizationContext filterContext) 
    { 
     if(this.IsProduction) 
      base.HandleNonHttpsRequest(filterContext); 
    } 
} 

Thiết kế giải thích:

  1. Môi trường sử dụng IsProduction() hoặc IsDevelopment() trên ví dụ: "#if DEBUG". Đôi khi chúng tôi phát hành/xuất bản ở chế độ DEBUG trên máy chủ thử nghiệm của chúng tôi và không muốn vô hiệu hóa yêu cầu bảo mật này. Điều này cần phải được vô hiệu hóa chỉ trong localhost/phát triển (kể từ khi chúng tôi quá lười biếng để thiết lập localhost SSL trong IIS Express hoặc bất cứ điều gì chúng tôi sử dụng tại địa phương).
  2. Sử dụng bộ lọc trong Startup.cs để thiết lập chung (vì chúng tôi muốn áp dụng điều này ở mọi nơi). Startup nên chịu trách nhiệm đăng ký và thiết lập tất cả các quy tắc toàn cầu. Nếu công ty của bạn sử dụng một nhà phát triển mới, cô ấy hy vọng sẽ tìm thấy thiết lập toàn cầu trong Startup.cs.
  3. Sử dụng RequireHttpsAttribute logic vì nó đã được chứng minh (bởi Microsoft). Điều duy nhất chúng tôi muốn thay đổi là khi logic được áp dụng (sản xuất) và khi nó không (phát triển/localhost). Không bao giờ sử dụng các chuỗi "huyền diệu" như "http: //" và "https: //" khi có thể tránh được bằng cách sử dụng lại thành phần Microsoft được tạo để cung cấp cùng một logic.

Ở trên, tôi sẽ xem xét giải pháp "thích hợp".

Lưu ý:

Là một thay thế, chúng ta có thể thực hiện một "lớp BaseController: điều khiển" và làm cho tất cả các bộ điều khiển của chúng tôi kế thừa từ "BaseController" (thay vì điều khiển). Sau đó, chúng tôi chỉ phải đặt thuộc tính 1 địa điểm toàn cầu (và không cần phải đăng ký bộ lọc trong Startup.cs).

Một số người thích kiểu thuộc tính. Xin lưu ý rằng điều này sẽ loại bỏ các lợi ích của quyết định thiết kế # 2.

Ví dụ về sử dụng:

[RequireHttpsInProductionAttribute] 
public class BaseController : Controller 
{ 
    // Maybe you have other shared controller logic.. 
} 

public class HomeController : BaseController 
{ 
    // Add endpoints (GET/POST) for Home controller 
} 
Các vấn đề liên quan