摘要华能集团下某发电厂的企业网站(基于AspNet实现不允许修改源程序)要求实现厂内用户可直接访问整个站点的所有页面厂外用户只能访问指定的页面的功能本文将按照需求分析方案设计编码实现部署应用的顺序逐步阐述整个解决方案的形成过程
需求分析
通过深入的交流和沟通确认了该发电厂在企业网站用户访问控制方面的改进要求大致情况如下
a) 网站基于AspNet实现不允许修改源程序
b) 厂内用户可直接访问整个站点的所有页面员工不需要身份验证
c) 厂外用户只能访问指定的页面
显而易见他们就是针对企业网站增加一项IP过滤功能在厂外用户访问某些敏感页面时将其拒之门外首先我们需要设置一个IP列表和一个Url列表前者包含所有厂内IP后者包含厂外用户可访问的全部Url并且这两个列表都是可维护的另外一个核心问题是我们需要选择一个合理的方式将开发好的功能模块集成到企业网站中HttpModules义不容辞
在AspNet时代IIS 接收到请求并将其调度给 aspnet_isapidll之后ASPNET 引擎开始逐个对已配置的HTTP模块(HttpModules)进行初始化然后再调用正确的HTTP处理程序并呈现被请求的资源最后将所生成的标记返回给 IIS 和请求客户端(如下图所示)
IIS 和 ASPNET 正在处理请求
如果你想了解更多关于HttpModules的资料请自行查阅
方案设计
开发环境
编程语言C#
开发工具Visual StudioNET
操作系统windows R
概要设计
使用HttpModules实现IP过滤功能的核心思想是自定义一个HttpModule捕获每一个用户请求然后获取相关的用户IP和被请求的Url进行逻辑判断将未授权的请求重定向到一个错误提示页Http请求授权与否的判断逻辑为
) 判断请求是否来自本地计算机是则自动忽略否则继续
) 判断用户IP是否属于内网(IP列表)是则忽略否则继续
) 判断被请求Url是否授权所有用户访问是则忽略否则继续
) 将请求重定向到错误提示页
在HttpApplication的BeginRequest事件中附加自定义的处理程序即可完成Http请求的捕获此外为了便于维护我们应将程序运行需要的各项参数(IP列表Url列表错误提示页路径等等)存储于特定的XML配置文件中为了提高效率我们还需要将配置文件执行内存级的缓存处理并对IPUrl匹配算法进行适当的优化
配置缓存算法
配置文件的缓存参照微软CommonServer项目中的实现逻辑将配置信息持久化为实体类存储于HttpContextCurrentCache中配置文件发生后缓存信息将自动清空下次访问时再次执行持久化操作
不需重启站点本文对CommonServer的缓存逻辑不做深入探讨感兴趣者可自行搜索相关资料
IP列表算法
通过上文可知当前项目用到的IP列表包含的数据量非常有限就是电厂web服务器可有效识别的内网IP的穷举
因而我们将整个IP列表缓存使用时直接检索当前用户IP是否存在于列表之中即可在具体IP的存储方面我们可将其视作进制将IP字符串转换为数字格式(例如可视作***+**+*+=不考虑IPV)在参数配置的格式方面我们应同时支持单个IP或IP段的方式增删IP列表
Url列表算法
就具体需求而言Url列表是一个授权外网用户访问的白名单换个说法对外网用户而言除了在列表之中的其他都不可访问一旦数据的安全级别降低会不会出现对外网用户而言除了列表之中的其他都可以访问的情况出现呢?为了兼容这种后续场景我们需要为Url列表定义一个是否黑名单(IsBlacklist)的附加参数另外对于动态网站穷举Url显然是不现实的不管是维护黑名单还是白名单所以我们可以转变一下思路更改最终Url为正则表达式即维护一个可匹配目标Url的正则表达式列表针对用户请求的具体Url逐个正则表达式执行匹配操作只要有一个匹配成功则认为当前Url存在于Url列表之中
编码实现
由于本文提供全部的c#源码下载所以本节仅对源码压缩包中的主要文件进行简要说明
DotCommonWebsiteFilter
│ DotCommonWebsiteFiltercfgxml
│ WebsiteFilterConfigurationcs
│ WebsiteFilterHttpModulecs
├─Util
│ GlobesCachecs
│ XmlAttributeReadercs
└─WebsiteFilter
IPMatchEnginecs
UrlMatchConditioncs
UrlMatchEnginecs
? DotCommonWebsiteFiltercfgxml
运行参数配置文件
? WebsiteFilterConfigurationcs
配置文件实体类
? WebsiteFilterHttpModulecs
实现了SystemWebIHttpModule接口的自定义Http模块
? GlobesCachecs
全局缓存操控类
? XmlAttributeReadercs
xml节点属性读取器
? IPMatchEnginecs
IP匹配引擎
? UrlMatchConditioncs
Url匹配条件(与正则表达式匹配)
? UrlMatchEnginecs
Url匹配引擎
WebsiteFilterHttpModulecs中BeginRequest自定义处理程序的核心代码如下
void context_BeginRequest(object sender EventArgs e)
{
if (HttpContextCurrentRequestIsLocal)//忽略本地计算机请求
return;
string ip = HttpContextCurrentRequestUserHostAddress;
if (!WebsiteFilterConfigurationGetConfig()PickedIPsIsMatch(ip))
{ //若在IP列表中找不到访客ip
string rawUrl = HttpContextCurrentRequestRawUrl;
UrlMatchEngine pu = WebsiteFilterConfigurationGetConfig()PickedUrls;
//列表包含当前url且列表为黑名单列表不包含当前url且列表不为黑名单 时需转向
//换而言之配备结果与是否黑名单取值一致时需转向
if (puIsMatch(rawUrl) == puIsBlacklist)
{ //非公开url自动重定向
HttpContextCurrentResponseRedirect(puErrorPage);
}
}
}
部署应用
DotCommonWebsiteFiltercfgxml配置文件
配置文件的根节点为DotCommon所有配置信息均为WebsiteFilter节点的子项PickedUrl节点对应Url列表IsBlacklist(是否)指示是否为黑名单ErrorPage指定错误提示页路径其子节点add可重复出现
通过pattern属性指定正则表达式文本上图所示配置表示仅网站首页(defaultaspx)允许外网用户访问
PickedIP节点对应IP列表有效子节点包括addremoveclear三项以上图为例第一个add指示内网ip为五个到第二行删除掉还剩两个到第三行再添加上最终的内网IP列表为三个
在企业网站中集成
配置好DotCommonWebsiteFiltercfgxml中的各项参数并拷贝到网站根目录
拷贝DotCommonWebsiteFilterdll文件到网站bin目录
在网站根目录下建立与配置文件中相对应的错误提示页(例如)
修改nfig在<httpModules>节点下注册WebsiteFilter模块代码如下
<httpModules>
<add name=WebsiteFilter
type=DotCommonWebsiteFilterHttpModule DotCommonWebsiteFilter/>
</httpModules>
分别从内网外网访问企业网站查看运行效果
结束语
本文仅针对具体需求阐述解决方案的构思过程希望对读者能有所帮助欢迎提出改进意见