`
897371388
  • 浏览: 523260 次
文章分类
社区版块
存档分类
最新评论

HTTPS跳转框架HTTP Security--Asp.net和ASP.NET MVC下可自由配置URL的HTTPS跳转框架

 
阅读更多

简介

一个简单易扩展的HTTP跳转HTTPS的框架。由配置文件配置规则,然后在HTTPMODULE里截获请求进行规则验证是否跳转HTTPS.

组成:

  1. web.config,用来配置规则
  2. HttpsConfiguration,用于读取配置文件
  3. HttpSecurityModule,用来截获请求触发规则验证
  4. RequestProcessor,用既有规则验证请求
  5. PathsMatcher,多路径(URL)匹配器
  6. PathMatcher,单URL路径匹配器
  7. PathMatcherFactory,用于创建StartsWith或Exact具体URL路径,可进行更多扩展,如正则表达式匹配。
  8. 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中实现正则验证就行了。



分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics