Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/visual-studio/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Asp.net mvc ASP.NET MVC仅在生产中需要TTP_Asp.net Mvc_Visual Studio_Ssl_Https - Fatal编程技术网

Asp.net mvc ASP.NET MVC仅在生产中需要TTP

Asp.net mvc ASP.NET MVC仅在生产中需要TTP,asp.net-mvc,visual-studio,ssl,https,Asp.net Mvc,Visual Studio,Ssl,Https,我想使用防止将不安全的HTTP请求发送到操作方法 C# VB _ 公共类控制器 _ 作为ActionResult的公共函数SomeAction() ... 端函数 末级 不幸的是,ASP.NET开发服务器不支持HTTPS 如何使我的ASP.NET MVC应用程序在发布到生产环境时使用RequireHttps,而不是在ASP.NET开发服务器上的开发工作站上运行时使用RequireHttps?如何在自定义属性中继承RequireHttps属性。然后,在自定义属性中,检查当前请求的IsLocal属

我想使用防止将不安全的HTTP请求发送到操作方法

C#

VB

_
公共类控制器
_
作为ActionResult的公共函数SomeAction()
...
端函数
末级
不幸的是,ASP.NET开发服务器不支持HTTPS


如何使我的ASP.NET MVC应用程序在发布到生产环境时使用RequireHttps,而不是在ASP.NET开发服务器上的开发工作站上运行时使用RequireHttps?

如何在自定义属性中继承RequireHttps属性。然后,在自定义属性中,检查当前请求的IsLocal属性,查看该请求是否来自本地计算机。如果是,则不要应用基本功能。否则,调用基本操作。

如果在开发工作站上运行版本构建,这将没有帮助,但条件编译可以完成这项工作

#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()
    {
    }

}
更新 在VisualBasic中,属性在技术上与它们应用于的定义是同一行的一部分。不能将条件编译语句放在一行中,因此必须编写两次函数声明—一次使用属性,一次不使用属性。不过,如果你不介意丑陋的话,它确实有效

#If Not Debug Then
    <RequireHttps()> _
    Function SomeAction() As ActionResult
#Else
    Function SomeAction() As ActionResult
#End If
        ...
    End Function
基本上,如果当前请求是本地的(即通过localhost访问站点),则新属性将退出,而不是运行默认的SSL授权代码。您可以这样使用它:

<RemoteRequireHttps()> _
Public Class SomeController

    <RemoteRequireHttps()> _
    Public Function SomeAction() As ActionResult
        ...
    End Function

End Class
_
公共类控制器
_
作为ActionResult的公共函数SomeAction()
...
端函数
末级

干净多了!前提是我的未测试代码确实有效。

如果可以派生和重写,请执行。如果不能-MVC附带源代码,只需获取源代码并创建自己的[ForceHttps]属性来检查IsLocal。

从RequireHttps派生是一个好方法

若要完全避开此问题,您也可以在本地计算机上使用IIS并使用自签名证书。IIS比内置的Web服务器更快,而且您的开发环境更像是生产环境


由于最初是ASP.Net开发服务器导致了您的问题,因此值得注意的是,Microsoft现在有了,它随Visual Studio一起提供(从VS2010 SP1开始)。这是IIS的精简版本,与开发服务器一样易于使用,但支持IIS 7.5的完整功能集,包括SSL


Scott Hanselman在上有一篇详细的帖子。

正如Joel提到的,您可以使用
#if!调试指令


我刚刚发现可以在web.config文件编译元素中更改调试符号的值。希望能有所帮助。

对于MVC 3,我添加了自己的FilterProvider(基于此处找到的代码:除其他外(为本地用户显示调试信息等),它将在
HttpContext.Request.IsLocal==false时使用
requireHttpAttribute
装饰所有操作,如果有人需要C版本:


利用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());
      }
    }

经过研究,我能够用IIS Express和重写控制器类的OnAuthorization方法(参考1)来解决这个问题。我也采用了Hanselman推荐的路线(参考2)。但是,由于两个原因,我对这两个解决方案并不完全满意: 1.Ref#1的授权仅在操作级别有效,而不在控制器类级别有效 2.参考#2需要大量的设置(用于makecert的Win7 SDK)、netsh命令,并且,为了使用端口80和端口443,我需要以管理员身份启动VS2010,对此我表示反对

因此,我提出了这个解决方案,它在以下条件下注重简单性:

  • 我希望能够在控制器类或操作级别使用RequireHttps attbbute

  • 我希望MVC在RequireHttps属性存在时使用HTTPS,如果不存在,则使用HTTP

  • 我不希望必须以管理员身份运行Visual Studio

  • 我希望能够使用IIS Express分配的任何HTTP和HTTPS端口(请参见注释1)

  • 我可以重用IIS Express的自签名SSL证书,我不在乎是否看到无效的SSL提示

  • 我希望开发、测试和生产具有完全相同的代码库和相同的二进制文件,并且尽可能独立于其他设置(例如,使用netsh、mmc证书管理单元等)

  • 现在,背景和解释已经讲完了,我希望这段代码能帮助一些人并节省一些时间。基本上,创建一个从Controller继承的BaseController类,并从这个基类派生控制器类。既然你已经读了这么多,我想你知道如何做这些。所以,祝你编码愉快

    注#1:这是通过使用有用的函数“getConfig”实现的(参见代码)

    参考文献1:

    参考文献2:

    ==========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);
        }
    
    ===================结束代码================

         #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);
        }
    
    在Web.Release.Config中,添加以下内容以清除HttpPort和HttpsPort(使用默认的80和443)


    一种解决方案,您可以在生产工作站和开发工作站上使用。它基于您在web.config中的应用程序设置选项

    <appSettings>
         <!--Use SSL port 44300 in IIS Express on development workstation-->
         <add key="UseSSL" value="44300" />
    </appSettings>
    
    别忘了在AccountController中修饰登录方法

    [RequireHttpsConditional]
    [HttpPost]
    public ActionResult LogOn(LogOnModel model, string returnUrl)
    
    在您的登录视图中使用类似的内容,以便通过https发布表单

    <% using (Html.BeginFormSecure("LogOn", "Account", new { ReturnUrl = Request.QueryString["ReturnUrl"] }, Request.IsSecureConnection, Request.Url)) { %>
    

    请参阅Rick Anderson在RickAndMSFT上发表的这篇文章,以及Azure和MVC填补Azure空白的文章

    MVC 6(ASP.NET Core 1.0):

    正确的解决方案是使用env.IsProduction()或env.IsDevelopment()。请阅读关于此答案背后原因的更多信息

    下面的简明答案(参见上面的链接阅读mo
    <appSettings>
    <add key="HttpPort" value="" xdt:Transform="SetAttributes" xdt:Locator="Match(key)"/>
    <add key="HttpsPort" value="" xdt:Transform="SetAttributes" xdt:Locator="Match(key)"/>
    </appSettings>
    
    <appSettings>
         <!--Use SSL port 44300 in IIS Express on development workstation-->
         <add key="UseSSL" value="44300" />
    </appSettings>
    
    public class RequireHttpsConditional : RequireHttpsAttribute
    {
        protected override void HandleNonHttpsRequest(AuthorizationContext filterContext)
        {
            var useSslConfig = ConfigurationManager.AppSettings["UseSSL"];
            if (useSslConfig != null)
            {
                if (!string.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
                {
                    throw new InvalidOperationException("The requested resource can only be accessed via SSL.");
                }
    
                var request = filterContext.HttpContext.Request;
                string url = null;
                int sslPort;
    
                if (Int32.TryParse(useSslConfig, out sslPort) && sslPort > 0)
                {
                    url = "https://" + request.Url.Host + request.RawUrl;
    
                    if (sslPort != 443)
                    {
                        var builder = new UriBuilder(url) {Port = sslPort};
                        url = builder.Uri.ToString();
                    }
                }
    
                if (sslPort != request.Url.Port)
                {
                    filterContext.Result = new RedirectResult(url);
                }
            }
        }
    }
    
    [RequireHttpsConditional]
    [HttpPost]
    public ActionResult LogOn(LogOnModel model, string returnUrl)
    
    <% using (Html.BeginFormSecure("LogOn", "Account", new { ReturnUrl = Request.QueryString["ReturnUrl"] }, Request.IsSecureConnection, Request.Url)) { %>
    
    public void ConfigureServices(IServiceCollection services)
    {
        // TODO: Register other services
    
        services.AddMvc(options =>
        {
            options.Filters.Add(typeof(RequireHttpsInProductionAttribute));
        });
    }
    
    [RequireHttpsInProductionAttribute]
    public class BaseController : Controller
    {
        // Maybe you have other shared controller logic..
    }
    
    public class HomeController : BaseController
    {
        // Add endpoints (GET / POST) for Home controller
    }
    
    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);
        }
    }
    
    private IHostingEnvironment CurrentEnvironment { get; set; }
    
    public Startup(IHostingEnvironment env)
    {
        CurrentEnvironment = env;
    }
    
    public void ConfigureServices(IServiceCollection services)
    {
        // additional services...
    
        services.AddMvc(options =>
        {
            if (!CurrentEnvironment.IsDevelopment())
            {
                options.Filters.Add(typeof(RequireHttpsAttribute));
            }
        });
    }
    
    ... 
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
            if (!Web.HttpContext.Current.IsDebuggingEnabled) {
                filters.Add(new RequireHttpsAttribute());   
            }
            ...
    }
    
    ... 
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
            if (Web.HttpContext.Current.IsCustomErrorEnabled) {
                filters.Add(new RequireHttpsAttribute());   
            }
            ...
    }