asp.net MVC 網站圖片防盜鏈的幾種方法

                                目錄css

1. 經過 URL Rewrite Module 組件html

2. 經過 nginx 圖片防盜鏈nginx

3.自定義 HttpHandler 處理web

4. 經過 MVC 自定義路由規則防盜鏈面試

5. 經過 MVC 自定義 RouteHandler 防盜鏈正則表達式

6. 經過 HttpModModule 防盜鏈json

7. 涉及知識點,相關資源windows

 

      

本身網站上的圖片被別的網站盜用是一件很使人厭惡的事情,下面是處理圖片盜鏈的幾種方法。服務器

在這裏先交代一下環境,我用的是 MVC4 ,IIS7 應用程序池爲集成模式,如下配置都是基於此環境進行。負載均衡

1. 經過 URL Rewrite Module 組件

這是一個比較簡單,方便的方法。首先要去 Url Rewite 官網 下載 URL Rewrite Module 2.0 並安裝。安裝完成後能夠看到 IIS設置裏多了  URL重寫 的模塊以下圖:

在這裏,能夠對URL訪問規則進行設置, 雙擊 URL 重寫,添加入站規則

     

   

 

 在條件(c)  裏面添加  {HTTP_REFERER}    模式爲: ^http://localhost/.*$, 意思是 請求  HTTP_REFERER 必須包含 http://localhost/ 字符,規則固然是根據本身的狀況寫。

添加保存後,站點的 web.config 文件的 system.webServer 節點下就多了 rewrite 節點,配置以下。

<system.webServer>
    <validation validateIntegratedModeConfiguration="false" />    
    <handlers>
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <remove name="OPTIONSVerbHandler" />
      <remove name="TRACEVerbHandler" /> 
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
        <rewrite>
            <rules>
                <rule name="防盜鏈" stopProcessing="true">
                    <match url=".*\.(gif|jpg|png)" />
                    <conditions> 
                        <add input="{HTTP_REFERER}" pattern="^http://localhost/.*$" negate="true" />
                    </conditions>
                    
                    <action type="Redirect" url="http://www.baidu.com" />
                </rule>
            </rules>
        </rewrite>
  </system.webServer>

配置好了,有沒有效果呢,咱們作一個測試頁面試試

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
</head>
<body>
    <img src="Content/webpage/img/111.jpg" />
    <img src="111.jpg"/>
</body>
</html>

      裏面有2張圖片,因爲在IIS 「入站規則條件」 裏面配置的  HTTP_REFERER  正則表達式爲 ^http://localhost/.*$  若是規則有效,咱們訪問 http://localhost/HtmlPage1.html  圖片應正常顯示,而若是經過  http://127.0.0.1/HtmlPage1.html  訪問是不該該顯示圖片的,下面是我經過這兩個地址訪問效果。

   

說明配置是成功的。固然了,URL Rewrite Module 並不是僅僅作圖片防盜鏈喲!

 

2. 經過 nginx 圖片防盜鏈

 

防盜鏈的原理都是同樣的,主要是經過 referer 判斷來源站點,若是來源站點不在 「白名單」 裏,則拒絕或返回一張默認圖片

 

location ~.*\.(jpg|gif|png)$ {
     valid_referers none blocked *.abc.com abc.com;
     if ($invalid_referer) {
     #rewrite ^/ http://abc.com/error.html;
     return 403;
      }
}
location ~.*\.(jpg|gif|png)$  表示全部 以 jpg|gif|png 爲後綴名的文件都進行防盜鏈處理
valid_referers none blocked *.abc.com abc.com;   驗證 referer  其中 none 表示直接訪問的,不存在referer   blocked爲根據防火牆假裝的 referer 
#rewrite ^/ http://abc.com/error.html;  若是圖片是放盜鏈,重定向到 地址 http://abc.com/error.html,通常是圖片地址,可是要注意,這個圖片地址不僅能在此防盜鏈規則裏,不然也訪問不到。

對 nginx 配置不熟悉的同窗請參考 windows 下配置 Nginx 常見問題

3.自定義 HttpHandler
處理

方法步驟: 1 建立自定義 handlers 代碼以下,根據 Referre 判斷請求來源,若是符合標準,輸出文件流,不然中止響應。也能夠輸出一個特定的圖片。
namespace WeiXinDemo.Globals
{
    /// <summary>
    /// 測試 Handler 實現圖片防盜鏈
    /// </summary>
    public class MyImgHandler : IHttpHandler
    {
        public bool IsReusable
        {
            get { return false; }
        }
         
        public void ProcessRequest(HttpContext context)
        {
            var response = context.Response;
            var request = context.Request; if (request.UrlReferrer == null || !WebApplication.ImgHost.Equals(request.UrlReferrer.Host))
            {
                response.End();
                return;
            }

            var fileName = context.Server.MapPath(request.FilePath);
            response.WriteFile(fileName);

            if (request.UrlReferrer == null || WebApplication.ImgHost.Equals(request.UrlReferrer.Host))
            {
                response.WriteFile(fileName);
            }
            else
            {
                response.End();
            }
        } 
    }
}


2 在web.config 文件 handlers 節點下添加自定義 Handler,知足要求的請求進入 WeiXinDemo.Globals.MyImgHandler 進行處理
<system.webServer> 
    <handlers>
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <remove name="OPTIONSVerbHandler" />
      <remove name="TRACEVerbHandler" />  
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    <!-- 這是添加的自定義Handler -->
<add name="jpgHandler" path="*.jpg" verb="*" type="WeiXinDemo.Globals.MyImgHandler,WeixinDemo" />
    <add name="pngHandler" path="*.png" verb="*" type="WeiXinDemo.Globals.MyImgHandler,WeixinDemo" />
<add name="bmpHandler" path="**.bmp" verb="*" type="WeiXinDemo.Globals.MyImgHandler,WeixinDemo" />
<add name="gifHandler" path="*.gif" verb="*" type="WeiXinDemo.Globals.MyImgHandler,WeixinDemo" />
</handlers> </system.webServer>

4. 經過 MVC 自定義路由規則防盜鏈

首先咱們要在 web.config 文件裏 system.webServer 節點下 設置<modules runAllManagedModulesForAllRequests="true" /> 同時還要在 RouteConfig.cs 文件裏添加 routes.RouteExistingFiles = true;確保全部路由都經過 RouteCollection 匹配 。
在這裏咱們須要瞭解 UrlRoutingModule,它是System.Web.Routing的一部分。UrlRoutingModule用於檢驗請求的url和本地硬盤 中的文件能不能相匹配。若是匹配,則交給IIS處理。若是不匹配它會檢驗 RouteCollection 來決定能不能繼續傳遞請求。而設置了 runAllManagedModulesForAllRequests="true" 後,會改變默認行爲,全部請求都需要 運用 Routing來處理。
<system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <modules runAllManagedModulesForAllRequests="true" />    
    <handlers>
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <remove name="OPTIONSVerbHandler" />
      <remove name="TRACEVerbHandler" /> 
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers> 
  </system.webServer>

     配置文件設置好之後添加自定義路由規則,下面是自定義路由規則的實現代碼,其實裏面就作了一件事,使用正則表達式判斷當前請求是否符合規則,若是符合規則,則進入指定的處理頁面,不然去匹配其餘的路由規則。

 
namespace WeiXinDemo.Globals
{
    /// <summary>
    /// 圖片路由規則(自定義)
    /// </summary>
    public class ImgRouteRule : IRouteConstraint
    {  
        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
        {
            var regex = new Regex(@"/[^/]+(.jpg|.bmp|.gif|.png)");
            var result = regex.IsMatch(httpContext.Request.RawUrl); 
            return result;
        }
    }
}
 

    這樣就形成了一個問題,全部的請求(好比 .css  .js  .htm 等等)都去路由規則裏面去匹配,若是在路由規則裏面匹配不到那麼就會返回 404,如何避免呢?經過 RouteConfig.cs 文件配置忽略。

public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            //確保全部路由都經過 RouteCollection 匹配(圖片防盜鏈)
            routes.RouteExistingFiles = true;

            //忽略 json,html,js,css文件
            routes.IgnoreRoute("{*pathInfo}", new { pathInfo = @".+(.json|.html|.js|.css)" });
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 //符合路由規則的轉到控制器 ImgRule/Index 處理 (自定義路由規則實現 圖片防盜鏈)
            routes.MapRoute(
                name: "ImagesRoute",
                url: "{*catchall}",
                defaults: new { controller = "ImgRule", action = "Index" },
                // ImgRouteRule 爲自定義路由規則,符合此規則,進入路由 訪問 ImgRule/Index 
                constraints: new { customConstraint = new ImgRouteRule() },
                //控制器類命名空間
                namespaces: new[] { "WeiXinDemo.Controllers" });

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );            
        }
    }

    在上面的代碼裏配置了 "ImagesRoute"   的路由,使用的自定義路由規則,當知足規則時,跳轉到 ImgRule/Index 去處理,處理代碼跟使用 HttpHandler 相似

 public class ImgRuleController : Controller
    {
        // GET: ImgRule
        public FileStreamResult Index()
        {
            var fPath = Server.MapPath("~" + Request.FilePath);
            if (Request.UrlReferrer == null)   return null;            

            if (!System.IO.File.Exists(fPath) || !WebApplication.ImgHost.Equals(Request.UrlReferrer.Host) || !WebApplication.ImgHost.Equals(Request.UrlReferrer.Host))            
                return null; 
            return GetFile(fPath);
        }

        private FileStreamResult GetFile(string fPath)
        { 
            return File(new FileStream(fPath, FileMode.Open, FileAccess.Read), GetContentType(Request.FilePath));
        }

        private static string GetContentType(string url)
        {
            switch (Path.GetExtension(url))
            {
                case ".gif":
                    return "Image/gif";
                case ".jpg":
                    return "Image/jpeg";
                case ".png":
                    return "Image/png";
                default:
                    break;
            }
            return null;
        }
    }

5. 經過
MVC 自定義 RouteHandler 防盜鏈
注意這裏是自定義路由,別跟第4種方法混淆了,這裏是指定自定義路由處理圖片。
1 web.config 文件配置同第4種方法,也要開啓 runAllManagedModulesForAllRequests="true"
2 建立自定義路由,自定義路實現代碼以下 ImageRouteHandler ,同時還有自定義路由調用的 HttpHandlerImageHandler
using System.IO;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Routing;

namespace WeiXinDemo.Globals
{
    /// <summary>
    /// 測試自定義 RouteHandler 圖片防盜鏈
    /// </summary>
    public class ImageRouteHandler : IRouteHandler
    {
        public IHttpHandler GetHttpHandler(RequestContext requestContext)
        { 
            return new ImageHandler();
        }
    }
     
    /// <summary>
    /// 自定義路由調用的 HttpHandler
    /// </summary>
    public class ImageHandler : IHttpHandler
    {
        public ImageHandler()
        {
            
        }
         
        public bool IsReusable
        {
            get
            {
                return true;
            }
        } 

        public void ProcessRequest(HttpContext context)
        {
            var response = context.Response;
            var request = context.Request; if (request.UrlReferrer == null || !WebApplication.ImgHost.Equals(request.UrlReferrer.Host))
            {
                response.End();
                return;
            }

            var fileName = context.Server.MapPath(request.FilePath);
            response.WriteFile(fileName);  
        }
    }
}

     RouteConfig.cs 文件配置 以下,這裏指定了 對根目錄下的 jpg 文件的訪問進入指定路由處理程序 ImageRouteHandler。    其實這裏能夠把圖片都放在某一個特定文件夾下,而後對這個文件夾下文件的訪問作放盜鏈。

namespace WeiXinDemo
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            //確保全部路由都經過 RouteCollection 匹配(圖片防盜鏈)
            routes.RouteExistingFiles = true;

            //忽略 json,html,js,css文件
            routes.IgnoreRoute("{*pathInfo}", new { pathInfo = @".+(.json|.html|.js|.css)" });
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            //圖片防盜鏈
            routes.Add("ImagesRoute",
                new Route("{name}.jpg", new ImageRouteHandler()));
 
            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
            
        }
    }
}

6. 經過
HttpModule 防盜鏈
1. 修改 web.config 配置文件  
<system.webServer>
    <modules runAllManagedModulesForAllRequests="true" >
      <add   name="ImgModule" type="WeiXinDemo.Globals.ImageModel,WeiXinDemo"/>
    </modules> 
    <handlers>
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <remove name="OPTIONSVerbHandler" />
      <remove name="TRACEVerbHandler" /> 
    </handlers>       
  </system.webServer>

2. 建立實現 IHttpModule 接口的 ImageModel

using System;
using System.Text.RegularExpressions;
using System.Web;

namespace WeiXinDemo.Globals
{
    /// <summary>
    /// 測試 HttpModel 圖片防盜鏈
    /// </summary>
    public class ImageModel : IHttpModule
    {
        public void Dispose()
        {
        }
public void Init(HttpApplication context) { context.BeginRequest += new EventHandler(BeginRequest); } void BeginRequest(object sender, EventArgs e) { HttpApplication context = (HttpApplication)sender; var regex = new Regex(@"/[^/]+(.jpg|.bmp|.gif|.png)"); var request = context.Context.Request; if (!regex.IsMatch(request.RawUrl)) return; if (request.UrlReferrer == null || !WebApplication.ImgHost.Equals(request.UrlReferrer.Host)) { context.Context.Response.End(); return; } var fileName = context.Context.Server.MapPath(request.FilePath); context.Context.Response.WriteFile(fileName); } } }

3.  RouteConfig.cs 文件忽略不須要防盜鏈的靜態資源

using System.Web.Mvc;
using System.Web.Routing;

namespace WeiXinDemo
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            //確保全部路由都經過 RouteCollection 匹配(圖片防盜鏈)
            routes.RouteExistingFiles = true;

            //忽略 json,html,js,css文件
            routes.IgnoreRoute("{*pathInfo}", new { pathInfo = @".+(.json|.html|.js|.css)" });
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );            
        }
    }
}

 

7. 涉及知識

本文只作了一件事情,圖片防盜鏈,其實從不一樣的實現方式來看它涉及到不一樣的知識。

1. URL Rewrite Module  組件的使用

 如何使用mod_rewrite模塊完成URL重寫

 Creating Rewrite Rules for the URL Rewrite Module

2.  Nginx

藉助Nginx搭建反向代理服務器

使用nginx實施負載均衡

3. IIS 工做原理,asp.net 管線

 IIS是如何處理ASP.NET請求的

ASP.NET那點鮮爲人知的事

IIS 內部運行機制

ASP.NET MVC5請求管道和生命週期

ASP.NET MVC請求處理管道生命週期的19個關鍵環節(1-6)

4. Mvc UrlRouting 處理機制

MVC以前的那點事兒系列(8):UrlRouting的理解

 

    本文只是在這裏探討了一下實現防盜鏈的方法,沒有考慮性能的問題,若是考慮性能跟簡便性,我我的喜歡用 第 1 和第 2種實現方式,第 3種 次之。 條條大路通羅馬,就看那種方法最適合。

相關文章
相關標籤/搜索