HTTPS跳转框架HTTP Security–Asp.net和ASP.NET MVC下可自由配置URL的HTTPS跳转框架
简介
一个简单易扩展的HTTP跳转HTTPS的框架。由配置文件配置规则,然后在HTTPMODULE里截获请求进行规则验证是否跳转HTTPS.
组成:
- web.config,用来配置规则
- HttpsConfiguration,用于读取配置文件
- HttpSecurityModule,用来截获请求触发规则验证
- RequestProcessor,用既有规是验证请求
- PathsMatcher,多路径(URL)匹配器
- PathMatcher,单URL路径匹配器
- PathMatcherFactory,用于创建StartsWith或Exact具体URL路径,可进行更多扩展,如正则表达式匹配。
- SecureRedirection,跳转HTTPS
WEB.CONFIG

- <configSections>
- <section name=”HttpsConfiguration” type=”ICStars2_0.Common.ConfigSections.HttpsConfiguration, ICStars2_0.Common, Version=1.0.0.0, Culture=neutral” />
- </configSections>
- <HttpsConfiguration mode=”On”>
- <paths>
- <add path=”/Test” />
- <add path=”/Account” security=”Ignore” />
- <add path=”/Account/Check.aspx” matchType=”Exact” />
- <add path=”/Member” matchType=”StartsWith” />
- </paths>
- </HttpsConfiguration>
mode选项On/Off, 开启或不开启HTTPS跳转
<add path=””/>, 添加一个URL验证规则。 默认security=”Secure”并且matchType=”StartsWith”
<add path=”” security=”” matchType=”” />,添加一个URL验证规则并设置具体选项。security选项Secure/Ignore,进行HTTPS跳转或忽略当前设置。matchType选项Exact/StartsWith,进行完全匹配或仅匹配开始字串。
HttpsConfiguration

- namespace ICStars2_0.Common.ConfigSections
- {
- public enum Mode
- {
- On,
- Off
- }
- public enum RequestSecurity
- {
- Secure,
- Ignore
- }
- public enum PathMatchType
- {
- Exact,
- StartsWith
- }
- internal sealed class ElementNames
- {
- internal const string Mode = “mode”;
- internal const string Paths = “paths”;
- internal const string MatchType = “matchType”;
- internal const string Path = “path”;
- internal const string Security = “security”;
- }
- public class HttpsConfiguration : ConfigurationSection
- {
- [ConfigurationProperty(ElementNames.Mode, DefaultValue = Mode.On)]
- public Mode Mode
- {
- get { return this[ElementNames.Mode] is Mode ? (Mode) this[ElementNames.Mode] : Mode.On; }
- }
- [ConfigurationProperty(ElementNames.Paths, IsRequired = true)]
- public HttpsPathCollection Paths
- {
- get
- {
- return this[ElementNames.Paths] as HttpsPathCollection;
- }
- }
- }
- public class HttpsPathCollection:ConfigurationElementCollection
- {
- public HttpsPath this[int index]
- {
- get
- {
- return base.BaseGet(index) as HttpsPath;
- }
- set
- {
- if (base.BaseGet(index) != null)
- {
- base.BaseRemoveAt(index);
- }
- this.BaseAdd(index, value);
- }
- }
- protected override ConfigurationElement CreateNewElement()
- {
- return new HttpsPath();
- }
- protected override object GetElementKey(ConfigurationElement element)
- {
- return ((HttpsPath)element).Path;
- }
- }
- public class HttpsPath:ConfigurationElement
- {
- [ConfigurationProperty(ElementNames.Path)]
- public string Path
- {
- get
- {
- return this[ElementNames.Path] as string;
- }
- }
- [ConfigurationProperty(ElementNames.MatchType, DefaultValue=PathMatchType.StartsWith)]
- public PathMatchType MatchType
- {
- get
- {
- return this[ElementNames.MatchType] is PathMatchType ? (PathMatchType) this[ElementNames.MatchType] : PathMatchType.Exact;
- }
- }
- [ConfigurationProperty(ElementNames.Security,DefaultValue=RequestSecurity.Secure)]
- public RequestSecurity Security
- {
- get
- {
- return this[ElementNames.Security] is RequestSecurity ? (RequestSecurity) this[ElementNames.Security] : RequestSecurity.Secure;
- }
- }
- }
- }
用于读取相应WEB.CONFIG中的信息。
HttpSecurityModule

- <httpModules>
- <add name=”SecuritySwitchModlue” type=”ICStars2_0.Framework.HttpSecurity.HttpSecurityModule, ICStars2_0.Framework, Version=1.0.0.0, Culture=neutral” />
- </httpModules>

- namespace ICStars2_0.Framework.HttpSecurity
- {
- public class HttpSecurityModule : IHttpModule
- {
- private HttpsConfiguration _config { get; set; }
- public void Init(HttpApplication context)
- {
- _config = ConfigurationManager.GetSection(“HttpsConfiguration”) as HttpsConfiguration; ;
- if (_config == null || _config.Mode == Mode.Off)
- {
- return;
- }
- context.BeginRequest += context_AcquireRequestState;
- }
- void context_AcquireRequestState(object sender, EventArgs e)
- {
- var application = sender as HttpApplication;
- RequestProcessor rp=new RequestProcessor(application.Context,_config);
- rp.Process();
- }
- public void Dispose()
- {
- }
- }
- }
配置HTTPMODULE,读取HTTPS跳转框架配置信息HttpsConfiguration,把截获的请求和读取的配置文件传递给请求处理器RequestProcessor。
RequestProcessor

- namespace ICStars2_0.Framework.HttpSecurity
- {
- internal class RequestProcessor
- {
- public HttpContext Context { get; set; }
- public HttpsConfiguration Config { get; set; }
- public RequestProcessor(HttpContext context,HttpsConfiguration config)
- {
- Context = context;
- Config = config;
- }
- public void Process()
- {
- if (Context.Request.IsSecureConnection) return;
- IEnumerable<HttpsPath> pathLIst = Config.Paths.Cast<HttpsPath>();
- var ignorePaths = pathLIst.Where(p => p.Security == RequestSecurity.Ignore);
- var securePaths = pathLIst.Where(p => p.Security == RequestSecurity.Secure);
- PathsMatcher ignoreMatcher = new PathsMatcher(Context,ignorePaths);
- if (ignoreMatcher.IsMatch()) return;
- PathsMatcher secureMatcher = new PathsMatcher(Context, securePaths);
- if (!secureMatcher.IsMatch()) return;
- SecureRedirection secureRedirection=new SecureRedirection(Context,null);
- secureRedirection.Go();
- }
- }
- }

- if (Context.Request.IsSecureConnection) return;
如果当前请求是HTTPS,则忽略。

- var ignorePaths = pathLIst.Where(p => p.Security == RequestSecurity.Ignore);
获取需要被忽略的URL规则集合

- var securePaths = pathLIst.Where(p => p.Security == RequestSecurity.Secure);
获取需要进行HTTPS跳转的URL规则集合

- PathsMatcher ignoreMatcher = new PathsMatcher(Context,ignorePaths);
- if (ignoreMatcher.IsMatch()) return;
创建忽略规则匹配器并使用需要被忽略的URL规则集合初始化,如果当前求匹配到任何一个忽略规则,则不进行HTTPS跳转。

- PathsMatcher secureMatcher = new PathsMatcher(Context, securePaths);
- if (!secureMatcher.IsMatch()) return;
- SecureRedirection secureRedirection=new SecureRedirection(Context,null);
- secureRedirection.Go();
创建需要进行HTTPS跳转的URL规则匹配器并初始化, 如果当前请求匹配到任何一个安全规则,则由SecureRedirection进行HTTPS跳转。
PathsMatcher

- namespace ICStars2_0.Framework.HttpSecurity
- {
- class PathsMatcher
- {
- public HttpContext Context { get; set; }
- public IEnumerable<HttpsPath> Paths { get; set; }
- public PathsMatcher(HttpContext context, IEnumerable<HttpsPath> paths)
- {
- Context = context;
- Paths = paths;
- }
- public bool IsMatch()
- {
- return Paths.Any(p => PathMatcherFactory.CreatePathMatcher(Context.Request.Url.AbsolutePath, p).IsMatch());
- }
- }
- }
多路径匹配器
PathMatcher

- namespace ICStars2_0.Framework.HttpSecurity
- {
- interface IPathMatcher
- {
- bool IsMatch();
- }
- }
- namespace ICStars2_0.Framework.HttpSecurity
- {
- internal class ExactPathMatcher:IPathMatcher
- {
- public string Path { get; set; }
- public string Pattern { get; set; }
- public ExactPathMatcher(string path, string pattern)
- {
- Path = path;
- Pattern = pattern;
- }
- public bool IsMatch()
- {
- return Path.Equals(Pattern, StringComparison.InvariantCultureIgnoreCase);
- }
- }
- }
- internal class StartsWithPathMatcher:IPathMatcher
- {
- public string Path { get; set; }
- public string Pattern { get; set; }
- public StartsWithPathMatcher(string path, string pattern)
- {
- Path = path;
- Pattern = pattern;
- }
- public bool IsMatch()
- {
- return Path.StartsWith(Pattern, StringComparison.InvariantCultureIgnoreCase);
- }
- }
单一路径匹配器,可扩展更多的匹配器
PathMatcherFactory

- internal class PathMatcherFactory
- {
- public static IPathMatcher CreatePathMatcher(string path, HttpsPath httpsPath)
- {
- switch (httpsPath.MatchType)
- {
- case PathMatchType.StartsWith:
- return new StartsWithPathMatcher(path, httpsPath.Path);
- case PathMatchType.Exact:
- return new ExactPathMatcher(path, httpsPath.Path);
- }
- return null;
- }
- }
匹配器工厂
SecureRedirection

- internal class SecureRedirection
- {
- public HttpContext Context { get; set; }
- public string TargetUrl { get; set; }
- public SecureRedirection(HttpContext context, string targetUrl)
- {
- Context = context;
- TargetUrl = targetUrl;
- }
- public void Go()
- {
- Context.Response.StatusCode = 301;
- Context.Response.RedirectLocation = TargetUrl ?? Context.Request.Url.AbsoluteUri.Replace(“http://”, “https://”);
- Context.Response.End();
- }
- }
将HTTP请求301重定向成HTTPS请求
总结
如果面对复杂的使用HTTPS的需求,这个框架能基本满足所有需要。当然由于我没有需求使用正则表达式验证,所以没有添加。但非常简单,可以在matchType里加一个“Regex”选项,创建一个新PathMather并在IsMatch中实现正则验证就行了。