asp.net-mvc ASP.NET MVC RequireHttps 仅在生产中
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1639707/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
ASP.NET MVC RequireHttps in Production Only
提问by Zack Peterson
I want to use the RequireHttpsAttributeto prevent unsecured HTTP requests from being sent to an action method.
我想使用RequireHttpsAttribute来防止将不安全的 HTTP 请求发送到操作方法。
C#
C#
[RequireHttps] //apply to all actions in controller
public class SomeController
{
[RequireHttps] //apply to this action only
public ActionResult SomeAction()
{
...
}
}
VB
VB
<RequireHttps()> _
Public Class SomeController
<RequireHttps()> _
Public Function SomeAction() As ActionResult
...
End Function
End Class
Unfortunately, ASP.NET Development Server doesn't support HTTPS.
不幸的是,ASP.NET 开发服务器不支持 HTTPS。
How can I make my ASP.NET MVC application use RequireHttps when published to the production environment, but not when run on my development workstation on the ASP.NET Development Server?
如何让我的 ASP.NET MVC 应用程序在发布到生产环境时使用 RequireHttps,但在 ASP.NET 开发服务器上的开发工作站上运行时不使用?
回答by Joel Mueller
This won't help if you run Release builds on your development workstation, but conditional compilation could do the job...
如果您在开发工作站上运行发布版本,这将无济于事,但条件编译可以完成这项工作......
#if !DEBUG
[RequireHttps] //apply to all actions in controller
#endif
public class SomeController
{
//... or ...
#if !DEBUG
[RequireHttps] //apply to this action only
#endif
public ActionResult SomeAction()
{
}
}
Update
更新
In Visual Basic, attributes are technically part of the same line as the definition they apply to. You can't put conditional compilation statements inside a line, so you're forced to write the function declaration twice - once with the attribute, and once without. It does work, though, if you don't mind the ugliness.
在 Visual Basic 中,属性在技术上与其应用的定义属于同一行。您不能将条件编译语句放在一行中,因此您不得不编写两次函数声明 - 一次使用属性,一次不使用。但是,如果您不介意丑陋,它确实有效。
#If Not Debug Then
<RequireHttps()> _
Function SomeAction() As ActionResult
#Else
Function SomeAction() As ActionResult
#End If
...
End Function
Update 2
更新 2
Several people have mentioned deriving from RequireHttpsAttributewithout providing an example, so here's one for you. I think that this approach would be much cleaner than the conditional compilation approach, and it would be my preference in your position.
有几个人提到了从RequireHttpsAttribute没有提供示例的情况下,所以这里有一个给你。我认为这种方法比条件编译方法要干净得多,这将是我在您的立场上的偏好。
DISCLAIMER: I haven't tested this code, even a little bit, and my VB is fairly rusty. All I know is that it compiles. I wrote it based on the suggestions of spot, queen3, and Lance Fisher. If it doesn't work, it should at least convey the general idea, and give you starting point.
免责声明:我还没有测试过这段代码,哪怕是一点点,而且我的 VB 相当生疏。我所知道的是它可以编译。我是根据 spot、queen3 和 Lance Fisher 的建议写的。如果它不起作用,它至少应该传达总体思路,并为您提供起点。
Public Class RemoteRequireHttpsAttribute
Inherits System.Web.Mvc.RequireHttpsAttribute
Public Overrides Sub OnAuthorization(ByVal filterContext As _
System.Web.Mvc.AuthorizationContext)
If IsNothing(filterContext) Then
Throw New ArgumentNullException("filterContext")
End If
If Not IsNothing(filterContext.HttpContext) AndAlso _
filterContext.HttpContext.Request.IsLocal Then
Return
End If
MyBase.OnAuthorization(filterContext)
End Sub
End Class
Basically, the new attribute just quits out instead of running the default SSL authorization code, if the current request is local (that is, you're accessing the site through localhost). You can use it like this:
基本上,如果当前请求是本地请求(即,您通过 localhost 访问站点),则新属性只是退出而不是运行默认的 SSL 授权代码。你可以这样使用它:
<RemoteRequireHttps()> _
Public Class SomeController
<RemoteRequireHttps()> _
Public Function SomeAction() As ActionResult
...
End Function
End Class
Much cleaner! Provided my un-tested code actually works.
干净多了!如果我未经测试的代码确实有效。
回答by mikesl
If anyone needs the C# version:
如果有人需要 C# 版本:
using System;
using System.Web.Mvc;
namespace My.Utils
{
public class MyRequireHttpsAttribute : RequireHttpsAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
if (filterContext.HttpContext != null && filterContext.HttpContext.Request.IsLocal)
{
return;
}
base.OnAuthorization(filterContext);
}
}
}
回答by Lance Fisher
Deriving from RequireHttps is a good approach.
从 RequireHttps 派生是一个很好的方法。
To side step the issue entirely, you can use IIS on your local machine with a self-signed certificate too. IIS is faster than the built-in webserver, and you have the advantage that your development environment is more like production.
为了完全解决这个问题,您也可以在本地计算机上使用带有自签名证书的 IIS。IIS 比内置网络服务器更快,而且您的优势在于您的开发环境更像是生产环境。
Scott Hanselman 拥有关于使用 VS2010 和 IIS Express 实现本地 HTTPS 的几种方法的大量资源。
回答by gt124
Leveraging the MVC filter system and Global.asax.cs, I'm assuming you could do this...
利用 MVC 过滤系统和 Global.asax.cs,我假设你可以做到这一点......
protected void Application_Start()
{
RegisterGlobalFilters(GlobalFilters.Filters);
}
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
if(Config.IsProduction) //Some flag that you can tell if you are in your production environment.
{
filters.Add(new RequireHttpsAttribute());
}
}
回答by Samuel Hyman
As it was the ASP.Net Development Server that caused your problem in the first place, it's worth noting that Microsoft now has IIS Express, which ships with Visual Studio (since VS2010 SP1). This is a cut-down version of IIS that is as easy to use as the Development Server, but supports the full feature set of IIS 7.5 including SSL.
由于首先是 ASP.Net 开发服务器导致了您的问题,因此值得注意的是,Microsoft 现在拥有IIS Express,它随 Visual Studio 一起提供(自 VS2010 SP1 起)。这是一个精简版的 IIS,与开发服务器一样易于使用,但支持 IIS 7.5 的完整功能集,包括 SSL。
Scott Hanselman has a detailed post on working with SSL in IIS Express.
Scott Hanselman 有一篇关于在 IIS Express 中使用 SSL的详细文章。
回答by spot
How about inheriting the RequireHttps attribute in a custom attribute. Then, inside your custom attribute, check the IsLocal property of the current request to see if the request is coming from the local machine. If it is, then do not apply the base functionality. Otherwise, call the base operation.
如何在自定义属性中继承 RequireHttps 属性。然后,在您的自定义属性中,检查当前请求的 IsLocal 属性以查看请求是否来自本地计算机。如果是,则不要应用基本功能。否则,调用基本操作。
回答by Eric Beijner
This worked for me, MVC 6 (ASP.NET Core 1.0). Code checks if debug is in development, and if not, ssl is not required. All edits are in Startup.cs.
这对我有用,MVC 6 (ASP.NET Core 1.0)。代码检查调试是否在开发中,如果不是,则不需要 ssl。所有编辑都在Startup.cs 中。
Add:
添加:
private IHostingEnvironment CurrentEnvironment { get; set; }
Add:
添加:
public Startup(IHostingEnvironment env)
{
CurrentEnvironment = env;
}
Edit:
编辑:
public void ConfigureServices(IServiceCollection services)
{
// additional services...
services.AddMvc(options =>
{
if (!CurrentEnvironment.IsDevelopment())
{
options.Filters.Add(typeof(RequireHttpsAttribute));
}
});
}
回答by juhan_h
For MVC 3 I added my own FilterProvider (based on code found here: Global and Conditional Filtersthat, among other things (displaying Debug info for local users etc.) will decorate all actions with RequireHttpsAttributewhen HttpContext.Request.IsLocal == false.
对于 MVC 3,我添加了我自己的 FilterProvider(基于此处找到的代码:全局和条件过滤器,除其他外(显示本地用户的调试信息等)将使用RequireHttpsAttributewhen装饰所有操作HttpContext.Request.IsLocal == false。
回答by queen3
If you can derive and override - do it. If you can't - MVC comes with sources, just take the sources and create your own [ForceHttps] attribute that checks IsLocal.
如果您可以派生和覆盖 - 那就去做吧。如果你不能 - MVC 带有源代码,只需获取源代码并创建您自己的 [ForceHttps] 属性来检查 IsLocal。
回答by Leng Keng
After researching aroud, I was able to solve this issue with IIS Express and an override of the Controller class's OnAuthorization method (Ref#1). I have also gone with the route recommended by Hanselman (Ref#2). However, I was not complete satisfied with these two solutions due to two reasons: 1. Ref#1's OnAuthorization only works at the action level, not at the controller class level 2. Ref#2 requires a lot of setup (Win7 SDK for makecert), netsh commands, and, in order to use port 80 and port 443, I need to launch VS2010 as administrator, which I frown upon.
经过一番研究,我能够通过 IIS Express 和对 Controller 类的 OnAuthorization 方法 (Ref#1) 的覆盖来解决这个问题。我也选择了 Hanselman (Ref#2) 推荐的路线。但是,我对这两个解决方案并不完全满意,原因有两个: 1. Ref#1 的 OnAuthorization 仅适用于操作级别,而不适用于控制器类级别 2. Ref#2 需要大量设置(Win7 SDK for makecert )、netsh 命令,并且,为了使用端口 80 和端口 443,我需要以管理员身份启动 VS2010,我对此不以为然。
So, I came up with this solution that focuses on simplicity with the following conditions:
所以,我想出了这个解决方案,它专注于具有以下条件的简单性:
I want to be able to use the RequireHttps attbbute at Controller class or action level
I want MVC to use HTTPS when the RequireHttps attribute is present, and use HTTP if it is absent
I do not want to have to run Visual Studio as administrator
I want to be able to use any HTTP and HTTPS ports that are assigned by IIS Express (See Note#1)
I can reuse the self-signed SSL cert of IIS Express, and I do not care if I see the invalid SSL prompt
I want dev, test, and production to have the exact same code base and same binary and as independent from additional setup (e.g. using netsh, mmc cert snap-in, etc.) as possible
我希望能够在控制器类或操作级别使用 RequireHttps attbbute
我希望MVC在RequireHttps属性存在时使用HTTPS,如果不存在则使用HTTP
我不想以管理员身份运行 Visual Studio
我希望能够使用 IIS Express 分配的任何 HTTP 和 HTTPS 端口(请参阅注释#1)
我可以重用IIS Express的自签名SSL证书,如果看到无效的SSL提示我不在乎
我希望开发、测试和生产具有完全相同的代码库和相同的二进制文件,并且尽可能独立于其他设置(例如使用 netsh、mmc 证书管理单元等)
Now, with the background and explanation out of the way, I hope this code will help someone and save some time. Basically, create a BaseController class that inherits from Controller, and derive your controller classes from this base class. Since you have read this far, I assume that you know how to do these. So, happy coding!
现在,抛开背景和解释,我希望这段代码能帮助某人并节省一些时间。基本上,创建一个继承自 Controller 的 BaseController 类,并从该基类派生您的控制器类。既然你已经读了这么多,我假设你知道如何做这些。所以,快乐编码!
Note#1: This is achieved by the use of a useful function 'getConfig' (see code)
注意#1:这是通过使用一个有用的函数“getConfig”来实现的(见代码)
Ref#1: http://puredotnetcoder.blogspot.com/2011/09/requirehttps-attribute-in-mvc3.html
参考#1:http: //puredotnetcoder.blogspot.com/2011/09/requirehttps-attribute-in-mvc3.html
Ref#2: http://www.hanselman.com/blog/WorkingWithSSLAtDevelopmentTimeIsEasierWithIISExpress.aspx
参考#2:http: //www.hanselman.com/blog/WorkingWithSSLAtDevelopmentTimeIsEasierWithIISExpress.aspx
========== Code in BaseController ===================
========== BaseController 中的代码 ====================
#region Override to reroute to non-SSL port if controller action does not have RequireHttps attribute to save on CPU
// By L. Keng, 2012/08/27
// Note that this code works with RequireHttps at the controller class or action level.
// Credit: Various stackoverflow.com posts and http://puredotnetcoder.blogspot.com/2011/09/requirehttps-attribute-in-mvc3.html
protected override void OnAuthorization(AuthorizationContext filterContext)
{
// if the controller class or the action has RequireHttps attribute
var requireHttps = (filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(typeof(RequireHttpsAttribute), true).Count() > 0
|| filterContext.ActionDescriptor.GetCustomAttributes(typeof(RequireHttpsAttribute), true).Count() > 0);
if (Request.IsSecureConnection)
{
// If request has a secure connection but we don't need SSL, and we are not on a child action
if (!requireHttps && !filterContext.IsChildAction)
{
var uriBuilder = new UriBuilder(Request.Url)
{
Scheme = "http",
Port = int.Parse(getConfig("HttpPort", "80")) // grab from config; default to port 80
};
filterContext.Result = this.Redirect(uriBuilder.Uri.AbsoluteUri);
}
}
else
{
// If request does not have a secure connection but we need SSL, and we are not on a child action
if (requireHttps && !filterContext.IsChildAction)
{
var uriBuilder = new UriBuilder(Request.Url)
{
Scheme = "https",
Port = int.Parse(getConfig("HttpsPort", "443")) // grab from config; default to port 443
};
filterContext.Result = this.Redirect(uriBuilder.Uri.AbsoluteUri);
}
}
base.OnAuthorization(filterContext);
}
#endregion
// a useful helper function to get appSettings value; allow caller to specify a default value if one cannot be found
internal static string getConfig(string name, string defaultValue = null)
{
var val = System.Configuration.ConfigurationManager.AppSettings[name];
return (val == null ? defaultValue : val);
}
============== end code ================
============== 结束代码 ================
In Web.Release.Config, add the following to clear out HttpPort and HttpsPort (to use the default 80 and 443).
在 Web.Release.Config 中,添加以下内容以清除 HttpPort 和 HttpsPort(使用默认的 80 和 443)。
<appSettings>
<add key="HttpPort" value="" xdt:Transform="SetAttributes" xdt:Locator="Match(key)"/>
<add key="HttpsPort" value="" xdt:Transform="SetAttributes" xdt:Locator="Match(key)"/>
</appSettings>

