我刚刚学习ASP.NET MVC,我最近发现[RequireHttps]属性自动重定向GET请求以使用SSL,就像这样......
[RequireHttps] //apply to all actions in controller
public class SomeController
{
[RequireHttps] //apply to this action only
public ActionResult SomeAction()
{
...
}
}
使用IIS Express作为开发服务器时,这会成功将请求从http://localhost:55945/...
重定向到https://localhost/...
。
但是在我的开发系统上,我的项目在端口44300上使用HTTPS(这是由Visual Studio 2010自动配置的),我还没有找到任何方法告诉MVC在重定向中使用该端口号,以便它会转到所需的https://localhost:43300/...
。
我真的希望这是自动的,因为Visual Studio会自动设置SSL端口号,据我所知,这必须影响所有使用MVC3中[RequireHttps]属性的开发人员。在我寻找解决方案时,我已经看到了一些不完整的“解决方案”解决方案,但似乎没有什么能够明确地“解决它”的正确方法。
所以“正确的方式”做什么,我要改变什么(在源代码或我的项目配置中)告诉MVC3中的[RequireHttps]属性使用我的项目配置的HTTPS端口使用
或者,在MVC3项目中是否有其他完全不同且更好的“正确方法”来设置SSL支持,这没有这个问题?
答案 0 :(得分:12)
RequireHttpsAttribute非常简单,无法进行参数化以重定向到特定端口。如果您真的需要这个,您可以创建一个子类并覆盖HandleNonHttpsRequest方法以不同方式组成重定向URL。
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);
}
但是,如果整个网站使用HTTPS运行,您只需在VS中配置Web项目属性(Web - >开始操作 - >开始URL),即可使用您的端口打开正确的HTTPS网址,而不是使用重定向本地测试功能。
答案 1 :(得分:3)
我有同样的问题,我正在使用RequireHttpsAttribute
中的Web.config
和网址重写规则来解决这个问题。重写规则与非标准端口号匹配,并在属性之前执行。您可以使用Web.config转换来删除部署中的重写规则,但是如果将其保留在其中则不会产生任何影响。在生产中,您将使用规则不匹配的标准端口号。然后该属性将捕获它。
以下是规则:
<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>
这种方法的缺点是在本地运行时不依赖于该属性。但如果您已经全局应用了一次,而不是将其添加到每个控制器,那我认为没问题。
答案 2 :(得分:2)
一些可能有帮助的事情。
此线程中有一个RequireHttpsAttribute源代码的版本:Where is the source for RequireHttpsAttribute?
在同一个线程上提到的codeplex上也有一个几乎相同的类,名为RequireSslAttribute。 http://aspnet.codeplex.com/SourceControl/changeset/view/63930#391756
以下是一个属性示例,可用于从http切换到https或基于TargetUriScheme属性反向切换。它还包括用于指定端口号的属性。
我选择在构造函数中使用#if DEBUG块来设置我在Debug配置下构建时的本地开发端口。这对我有用,因为我总是在部署时在发布版本下构建,在这种情况下,端口号将默认为null并且将被排除在url之外。
将属性应用于操作方法时,也可以设置端口号。我还可以看到将这些连接到配置文件或其他配置源以确定运行时的端口号。
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);
}
}
答案 3 :(得分:0)
我很困惑为什么我不得不花费数小时试图做到这一点。我做了一个URL重写,类似于Scott Hanselman在这里解释的方式:
http://www.hanselman.com/blog/WorkingWithSSLAtDevelopmentTimeIsEasierWithIISExpress.asp X
这非常有效,我只是在生产网络服务器上取出重写规则。