如何在基於ASP.NET MVC的網站中爲某些頁面使用HTTPS?ASP.NET MVC下的SSL頁面
史蒂夫·桑德森對如何在做到這一點在乾燥的方式上預覽4一個不錯的教程:
http://blog.codeville.net/2008/08/05/adding-httpsssl-support-to-aspnet-mvc-routing/
是否與預覽5?
如何在基於ASP.NET MVC的網站中爲某些頁面使用HTTPS?ASP.NET MVC下的SSL頁面
史蒂夫·桑德森對如何在做到這一點在乾燥的方式上預覽4一個不錯的教程:
http://blog.codeville.net/2008/08/05/adding-httpsssl-support-to-aspnet-mvc-routing/
是否與預覽5?
如果您正在使用ASP.NET MVC 2 Preview 2 or higher,你現在可以簡單地使用:
[RequireHttps]
public ActionResult Login()
{
return View();
}
雖然,命令的參數值得注意的是,作爲mentioned here。
更好/更新的方式有些ActionLink的擴展:http://www.squaredroot.com/post/2008/06/11/MVC-and-SSL.aspx 或者重定向到https的控制器action屬性:// http://forums.asp.net/p/1260198/2358380.aspx#2358380
這裏有一個blog post by Pablo M. Cibrano˚F rom 2009年1月收集了一些技巧,包括HttpModule和擴展方法。
這是使用ActionFilter的blog post by Adam Salvo。
確保你看到他自己寫的後續文章:http://blog.salvoz.com/2009/04/25/PartialSSLAndAuthorizationWithAspNetMVCRevisited.aspx – 2009-07-12 19:49:55
MVCFutures有'RequireSSL'屬性。
(感謝亞當爲pointing that out在更新的博文)
只要將它應用到你的操作方法,以「重定向=真正的」如果你想要一個http://請求自動變成https://開頭:
[RequireSsl(Redirect = true)]
我是否需要繼承它以處理本地主機請求? – 2009-11-05 02:46:41
一種方法是爲本地機器創建證書並使用它。我認爲完全禁用它的本地主機,你確實需要子類或重複的代碼。不知道推薦的方法是什麼 – 2009-11-05 07:46:34
看起來它是密封的,所以我需要重複代碼。遊民。 本地機器的證書只能在IIS中正常工作,而不是開發Web服務器。 – 2009-11-05 16:55:48
下面是從丹Wahlin最近的文章對這個:
http://weblogs.asp.net/dwahlin/archive/2009/08/25/requiring-ssl-for-asp-net-mvc-controllers.aspx
他使用ActionFilter屬性。
由於Amadiere wrote,[RequireHttps]在MVC 2 進入 HTTPS的偉大工程。但是,如果您只想按照您的說法使用HTTPS 一些頁面,那麼MVC 2不會給您任何愛 - 一旦它將用戶切換到HTTPS,它們就會一直停留在那裏,直到您手動重定向它們。
我使用的方法是使用另一個自定義屬性[ExitHttpsIfNotRequired]。當連接到控制器或動作,這將重定向到HTTP如果:
這裏有點太大而不能在這裏發佈,但你可以看到the code here加上一些額外的細節。
這不一定是MVC具體的,但這種方法確實工作既ASP.NET WebForms和MVC:
http://www.codeproject.com/KB/web-security/WebPageSecurity_v2.aspx
我已經使用了好幾年,並像關注分離和通過web.config文件進行管理。
對於那些誰不是面向屬性的開發方法風扇,這裏是一段代碼,可以幫助:
public static readonly string[] SecurePages = new[] { "login", "join" };
protected void Application_AuthorizeRequest(object sender, EventArgs e)
{
var pageName = RequestHelper.GetPageNameOrDefault();
if (!HttpContext.Current.Request.IsSecureConnection
&& (HttpContext.Current.Request.IsAuthenticated || SecurePages.Contains(pageName)))
{
Response.Redirect("https://" + Request.ServerVariables["HTTP_HOST"] + HttpContext.Current.Request.RawUrl);
}
if (HttpContext.Current.Request.IsSecureConnection
&& !HttpContext.Current.Request.IsAuthenticated
&& !SecurePages.Contains(pageName))
{
Response.Redirect("http://" + Request.ServerVariables["HTTP_HOST"] + HttpContext.Current.Request.RawUrl);
}
}
有幾個原因,以避免屬性,其中之一是,如果你想要查看所有受保護頁面的列表,您必須跳過解決方案中的所有控制器。
我去翻過這個問題,希望我的解決方案可以幫助別人。
我們得到了幾個問題: - 我們需要保護的具體行動,例如「登錄」,在「帳戶」。我們可以使用RequireHttps屬性中的構建,這非常棒 - 但它會使用https://重定向到我們。 - 我們應該製作我們的鏈接,表單和諸如「SSL知曉」。
一般情況下,我的解決方案允許指定將使用絕對URL,除了指定協議的能力路線。您可以使用此批准來指定「https」協議。
所以,首先我創建了一個ConnectionProtocol枚舉:
/// <summary>
/// Enum representing the available secure connection requirements
/// </summary>
public enum ConnectionProtocol
{
/// <summary>
/// No secure connection requirement
/// </summary>
Ignore,
/// <summary>
/// No secure connection should be used, use standard http request.
/// </summary>
Http,
/// <summary>
/// The connection should be secured using SSL (https protocol).
/// </summary>
Https
}
RequireSsl的現在,我已經創建手卷版本。我修改了原始的RequireSsl源代碼,允許重定向回http:// urls。另外,我已經把一個領域,使我們能夠確定我們是否應該要求SSL或沒有(我用它與DEBUG預處理器)。現在
/* Note:
* This is hand-rolled version of the original System.Web.Mvc.RequireHttpsAttribute.
* This version contains three improvements:
* - Allows to redirect back into http:// addresses, based on the <see cref="SecureConnectionRequirement" /> Requirement property.
* - Allows to turn the protocol scheme redirection off based on given condition.
* - Using Request.IsCurrentConnectionSecured() extension method, which contains fix for load-balanced servers.
*/
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public sealed class RequireHttpsAttribute : FilterAttribute, IAuthorizationFilter
{
public RequireHttpsAttribute()
{
Protocol = ConnectionProtocol.Ignore;
}
/// <summary>
/// Gets or sets the secure connection required protocol scheme level
/// </summary>
public ConnectionProtocol Protocol { get; set; }
/// <summary>
/// Gets the value that indicates if secure connections are been allowed
/// </summary>
public bool SecureConnectionsAllowed
{
get
{
#if DEBUG
return false;
#else
return true;
#endif
}
}
public void OnAuthorization(System.Web.Mvc.AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
/* Are we allowed to use secure connections? */
if (!SecureConnectionsAllowed)
return;
switch (Protocol)
{
case ConnectionProtocol.Https:
if (!filterContext.HttpContext.Request.IsCurrentConnectionSecured())
{
HandleNonHttpsRequest(filterContext);
}
break;
case ConnectionProtocol.Http:
if (filterContext.HttpContext.Request.IsCurrentConnectionSecured())
{
HandleNonHttpRequest(filterContext);
}
break;
}
}
private void HandleNonHttpsRequest(AuthorizationContext filterContext)
{
// only redirect for GET requests, otherwise the browser might not propagate the verb and request
// body correctly.
if (!String.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException("The requested resource can only be accessed via SSL.");
}
// redirect to HTTPS version of page
string url = "https://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl;
filterContext.Result = new RedirectResult(url);
}
private void HandleNonHttpRequest(AuthorizationContext filterContext)
{
if (!String.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException("The requested resource can only be accessed without SSL.");
}
// redirect to HTTP version of page
string url = "http://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl;
filterContext.Result = new RedirectResult(url);
}
}
,這RequireSsl將做您的要求以下基本屬性值: - 忽略:不會做什麼。 - Http:將強制重定向到http協議。 - Https:將強制重定向到https協議。
你應該建立自己的基地控制器和設置該屬性爲HTTP。
[RequireSsl(Requirement = ConnectionProtocol.Http)]
public class MyController : Controller
{
public MyController() { }
}
現在,在每個需要SSL的cpntroller/action中,只需使用ConnectionProtocol.Https設置此屬性即可。
現在讓我們轉移到網址:我們得到了與URL路由引擎幾個問題。您可以通過http://blog.stevensanderson.com/2008/08/05/adding-httpsssl-support-to-aspnet-mvc-routing/瞭解更多關於它們的信息。在這篇文章中提出的解決方案理論上很好,但很老,我不喜歡這種方法。
我的解決方案如下: 創建基本的 「路」 類的子類:
公共類AbsoluteUrlRoute:路線 { #地區的構造函數
/// <summary>
/// Initializes a new instance of the System.Web.Routing.Route class, by using
/// the specified URL pattern and handler class.
/// </summary>
/// <param name="url">The URL pattern for the route.</param>
/// <param name="routeHandler">The object that processes requests for the route.</param>
public AbsoluteUrlRoute(string url, IRouteHandler routeHandler)
: base(url, routeHandler)
{
}
/// <summary>
/// Initializes a new instance of the System.Web.Routing.Route class, by using
/// the specified URL pattern and handler class.
/// </summary>
/// <param name="url">The URL pattern for the route.</param>
/// <param name="defaults">The values to use for any parameters that are missing in the URL.</param>
/// <param name="routeHandler">The object that processes requests for the route.</param>
public AbsoluteUrlRoute(string url, RouteValueDictionary defaults, IRouteHandler routeHandler)
: base(url, defaults, routeHandler)
{
}
/// <summary>
/// Initializes a new instance of the System.Web.Routing.Route class, by using
/// the specified URL pattern and handler class.
/// </summary>
/// <param name="url">The URL pattern for the route.</param>
/// <param name="defaults">The values to use for any parameters that are missing in the URL.</param>
/// <param name="constraints">A regular expression that specifies valid values for a URL parameter.</param>
/// <param name="routeHandler">The object that processes requests for the route.</param>
public AbsoluteUrlRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints,
IRouteHandler routeHandler)
: base(url, defaults, constraints, routeHandler)
{
}
/// <summary>
/// Initializes a new instance of the System.Web.Routing.Route class, by using
/// the specified URL pattern and handler class.
/// </summary>
/// <param name="url">The URL pattern for the route.</param>
/// <param name="defaults">The values to use for any parameters that are missing in the URL.</param>
/// <param name="constraints">A regular expression that specifies valid values for a URL parameter.</param>
/// <param name="dataTokens">Custom values that are passed to the route handler, but which are not used
/// to determine whether the route matches a specific URL pattern. These values
/// are passed to the route handler, where they can be used for processing the
/// request.</param>
/// <param name="routeHandler">The object that processes requests for the route.</param>
public AbsoluteUrlRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints,
RouteValueDictionary dataTokens, IRouteHandler routeHandler)
: base(url, defaults, constraints, dataTokens, routeHandler)
{
}
#endregion
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
var virtualPath = base.GetVirtualPath(requestContext, values);
if (virtualPath != null)
{
var scheme = "http";
if (this.DataTokens != null && (string)this.DataTokens["scheme"] != string.Empty)
{
scheme = (string) this.DataTokens["scheme"];
}
virtualPath.VirtualPath = MakeAbsoluteUrl(requestContext, virtualPath.VirtualPath, scheme);
return virtualPath;
}
return null;
}
#region Helpers
/// <summary>
/// Creates an absolute url
/// </summary>
/// <param name="requestContext">The request context</param>
/// <param name="virtualPath">The initial virtual relative path</param>
/// <param name="scheme">The protocol scheme</param>
/// <returns>The absolute URL</returns>
private string MakeAbsoluteUrl(RequestContext requestContext, string virtualPath, string scheme)
{
return string.Format("{0}://{1}{2}{3}{4}",
scheme,
requestContext.HttpContext.Request.Url.Host,
requestContext.HttpContext.Request.ApplicationPath,
requestContext.HttpContext.Request.ApplicationPath.EndsWith("/") ? "" : "/",
virtualPath);
}
#endregion
}
此版本的 「路線」 的類將創建絕對網址。這裏的訣竅,以及博客文章作者的建議,是使用DataToken來指定方案(例如結尾:))。
現在,如果我們要生成一個url,例如路徑「Account/LogOn」,我們會得到「/ http://example.com/Account/LogOn」 - 這是因爲UrlRoutingModule將所有的url視爲相對的。我們可以修復使用自定義的HttpModule:
public class AbsoluteUrlRoutingModule : UrlRoutingModule
{
protected override void Init(System.Web.HttpApplication application)
{
application.PostMapRequestHandler += application_PostMapRequestHandler;
base.Init(application);
}
protected void application_PostMapRequestHandler(object sender, EventArgs e)
{
var wrapper = new AbsoluteUrlAwareHttpContextWrapper(((HttpApplication)sender).Context);
}
public override void PostResolveRequestCache(HttpContextBase context)
{
base.PostResolveRequestCache(new AbsoluteUrlAwareHttpContextWrapper(HttpContext.Current));
}
private class AbsoluteUrlAwareHttpContextWrapper : HttpContextWrapper
{
private readonly HttpContext _context;
private HttpResponseBase _response = null;
public AbsoluteUrlAwareHttpContextWrapper(HttpContext context)
: base(context)
{
this._context = context;
}
public override HttpResponseBase Response
{
get
{
return _response ??
(_response =
new AbsoluteUrlAwareHttpResponseWrapper(_context.Response));
}
}
private class AbsoluteUrlAwareHttpResponseWrapper : HttpResponseWrapper
{
public AbsoluteUrlAwareHttpResponseWrapper(HttpResponse response)
: base(response)
{
}
public override string ApplyAppPathModifier(string virtualPath)
{
int length = virtualPath.Length;
if (length > 7 && virtualPath.Substring(0, 7) == "/http:/")
return virtualPath.Substring(1);
else if (length > 8 && virtualPath.Substring(0, 8) == "/https:/")
return virtualPath.Substring(1);
return base.ApplyAppPathModifier(virtualPath);
}
}
}
}
由於該模塊是壓倒UrlRoutingModule的基本實現,我們應該卸下底座HTTP模塊,並在web.config中註冊我們的。所以,在「system.web」下設置:
<httpModules>
<!-- Removing the default UrlRoutingModule and inserting our own absolute url routing module -->
<remove name="UrlRoutingModule-4.0" />
<add name="UrlRoutingModule-4.0" type="MyApp.Web.Mvc.Routing.AbsoluteUrlRoutingModule" />
</httpModules>
那就是:)。
爲了註冊一個絕對/協議遵循的路線,你應該做的:
routes.Add(new AbsoluteUrlRoute("Account/LogOn", new MvcRouteHandler())
{
Defaults = new RouteValueDictionary(new {controller = "Account", action = "LogOn", area = ""}),
DataTokens = new RouteValueDictionary(new {scheme = "https"})
});
會喜歡聽到你的反饋+的改進。希望它可以幫助! :)
編輯: 我忘了包括IsCurrentConnectionSecured()擴展方法(太多的片段:P)。這是一種通常使用Request.IsSecuredConnection的擴展方法。然而,當使用負載均衡時,這種方法無效 - 所以這種方法可以繞過這個(從nopCommerce中獲取)。
/// <summary>
/// Gets a value indicating whether current connection is secured
/// </summary>
/// <param name="request">The base request context</param>
/// <returns>true - secured, false - not secured</returns>
/// <remarks><![CDATA[ This method checks whether or not the connection is secured.
/// There's a standard Request.IsSecureConnection attribute, but it won't be loaded correctly in case of load-balancer.
/// See: <a href="http://nopcommerce.codeplex.com/SourceControl/changeset/view/16de4a113aa9#src/Libraries/Nop.Core/WebHelper.cs">nopCommerce WebHelper IsCurrentConnectionSecured()</a>]]></remarks>
public static bool IsCurrentConnectionSecured(this HttpRequestBase request)
{
return request != null && request.IsSecureConnection;
// when your hosting uses a load balancer on their server then the Request.IsSecureConnection is never got set to true, use the statement below
// just uncomment it
//return request != null && request.ServerVariables["HTTP_CLUSTER_HTTPS"] == "on";
}
MVC 6(ASP.NET核心1.0)正在與Startup.cs略有不同。
要在所有頁面上使用RequireHttpsAttribute(如Amadiere的answer中所述),您可以將其添加到Startup.cs中,而不是在每個控制器上使用屬性樣式(或者不是爲所有控制器創建一個BaseController來繼承) 。
Startup.cs - 註冊過濾器:
public void ConfigureServices(IServiceCollection services)
{
// TODO: Register other services
services.AddMvc(options =>
{
options.Filters.Add(typeof(RequireHttpsAttribute));
});
}
有關的設計決定了上述方法的詳細信息,請參閱我在類似的問題有關how to exclude localhost requests from being handled by the RequireHttpsAttribute答案。
這是非常過時的。對於MVC4及更高版本,請參閱我的博文http://blogs.msdn.com/b/rickandy/archive/2012/03/23/securing-your-asp-net-mvc-4-app-and-the-new -allowanonymous-attribute.aspx – RickAndMSFT 2014-02-19 02:15:51