7 Şubat 2011 Pazartesi

HttpHandler ile güvenli dosya paylaşımı.

 Bildiğiniz gibi web yapısında herşey request-response mantığı içinde devam eder. Bir istek (request) sunucuya gelince, hangi tanımlanmış kod'un (ddl,class,exe,ashx ) bu istekle ilgilenip bir cevap döneceği handler ( kotarıcı, işleyici) kavramını oluşturur. Varsayılan olarak aspx,ascx, vb bir çok dosyanın bir handleri vardır. ve bu handler atamasına IIS arayüzünden erişebilirsiniz.


Normalde bir rar, zip, pdf gibi dosyalar sunucudan istenince download edilebilir şekilde clienta gelirler. yani clietn istemci yani web tarayıcılar bu dosyaları indirme veya açma işlemini yapabilirler. Biz eğer kendimiz bu dosya tiplerine bir handler yazarsak şifreyi doğru girmeye kullanıcılara dosyalarımızı göndermeyebiliriz. Doğru girdiklerinde ise normal handler ne yapıyorsa o şekilde dosyayı istemciye yollarız

Öncelikle bir kaç rar dosyası bulup bunlardan bazılarını uygulama kök dizinimize bir kısmınıda \secureshare klasörü altına kopyalayalım. sonra bu dosyalara browse edeciğimiz webform1.aspx gibi bir sayfada link verelim.

webform1.aspx'den :


  <hr>
        güvenli içerik : <br />
    <a href="secureshare/a.rar">a.rar</a><br />
     <a href="secureshare/b.rar">b.rar</a> <br />
     <a href="secureshare/c.rar">c.rar</a><br />
     <a href="secureshare/d.rar">d.rar</a>
  
     <hr />
       şifresiz- içerik : <br />
       <a href="a1.rar" >a1.rar</a><br />
       <a href="d1.rar" >d1.rar</a>
  



projemize  yeni  bir "Generic Handler"  ekleyerek içine aşağıdaki kodları yazalım.
Handler2.ashx.cs  kodu :


// ekstra eklenen using’ler :
using System.Web.SessionState;  // session kullanımı için
using System.IO;   //  fileinfo için dosya uznatısına göre contenttype


namespace WebApplication1
{
    public class DosyaHandler : IHttpHandler, IRequiresSessionState
    {


        /*   session'ı handler içinde kullanabilmek için yukarıdaki
            IRequiresSessionState interface'ini  inherit   etmemiz gerekli.
        */


        public void ProcessRequest(HttpContext context)
        {

            HttpRequest req = context.Request;


            /* kullanıcı doğru şifreyi girdi ise session objemizde istediğimiz değer vardır.
             * İstenen dosyanın contenttype'ını   al ve client'a gönder.
            */


            if(context.Session["tamam"]!=null && context.Session["tamam"].ToString()=="1")
            {

                string dosya = req.PhysicalPath;
                context.Response.ContentType = GetContentType(dosya);
                context.Response.TransmitFile(dosya);
                context.Response.End();

            }
            else
            {
             /*
              şifre girilmedi ise sessindaki değerimiz boş  istenen dosyayı session'a at.
               sonra login   sayfasına yönlendir isteği.
             */

               string sayfa=req.CurrentExecutionFilePath;
                context.Session["dosya"]=sayfa;
               context.Response.Redirect(@"~\login.aspx");
              
            }
           


        }


        /*
             dosya uzantısından contenttype bulan fonksiyon. diğer content typeler aşağıdaki linki
            verilen siteden bulunabilir
        */

        private string GetContentType(string filename)
        {

            // http://reliableanswers.com/contenttype/ctype.asp?ord=subs

            string ct = null;
            FileInfo fileinfo = new FileInfo(filename);

            if (fileinfo.Exists)
            {
                switch (fileinfo.Extension.Remove(0, 1).ToLower())
                {
                    case "pdf":
                        {
                            ct = "application/pdf";
                            break;
                        }
                    case "rar":
                        {
                            ct = "application/x-rar-compressed";
                            break;
                        }
                    case "zip":
                        {
                            ct = "application/x-zip-compressed";
                            break;
                        }
                    case "exe":
                        {
                            ct = "application/x-msdownload";
                            break;
                        }

                        
                }

                return ct;
            }

            return null;
        }

       
       
        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }

}




login.aspx sayfamız :

<
div>
       Şifre: <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
        <asp:Button ID="Button1" runat="server" onclick="Button1_Click" Text="Button" />
        <asp:Label ID="Label1" runat="server"></asp:Label>
</div>

basit bir sayfa yaptık demo için siz her dosya için yda grup grup değişik bir mekanizma oluşturabilirsiniz.

login.aspx.cs  kodu

       protected void Button1_Click(object sender, EventArgs e)
        {
            if (TextBox1.Text == "1")
            {
                Session["tamam"] = "1";

                string sayfa = Session["dosya"].ToString();
                Response.Redirect(sayfa);


            }
            else
            {
                Session["tamam"] = null;
                Label1.Text = "hatalı şifre!";
            }
        }





görüldüğü gibi şifre doğru ise session'da dosya indirmek için aradığımız değeri  kaydediyoruz. Login sayfasına gelmeden önce hangi dosya talep edilmiş ise o da session'da kayıtlı olduğu için giriş doğrulanınca isteği tekrar o dosyaya yönlendiriyoruz.


evet şu ana kadar yaptıklarımız sadece alt yapı idi. eğer web.config de son bağı koymaz ise bu yaptıklarımız sadece bir kod parçası olarak kalır ve bizim dosyalarımızı normal şekilde download edilir.  evet normalde IIS de yapılan mapping olayını biz web.config üzerinden  özelleştireceğiz (customize).  evet sadece  rar uzantılı dosyalar için demo'muzu yapıyoruz benzer diğer uzantılar için tek tek girilmesi gereki handler' kayıtlarının.  web.config <httphandlers> tag'i

     <httpHandlers>
        <add verb="*"  path="*/secureshare/*.rar" type="WebApplication1.DosyaHandler,  WebApplication1" />
     </httpHandlers>


verb parametresi ile handlerin  GET,POST, vb hangi tip istekte çalışacağını belirler. Path parametresi dosyanın ya açık adı yada wildcard ile yazılmış şekli.  burada biz  görüldüğü gibi sadece   secureshare klasöründen çağrılacak (request edilecek)  rar uzantılı dosyaları kendi özel handler'ımıza yönlendirdik.  diğer klasördeki rarlar normal IIS davranışı nasıl ise o şekilde cevaplanır.

  örnek uygulama kodları indirmek için tıklayınız

Hiç yorum yok: