Tags: , , , , , , | Categories: asp.net, c#, Dynamic Data Posted by Admin on 12/19/2010 11:06 AM | Comments (0)

Merhabalar, bu yazıda dynamic data ile kullanıcı arayüzünde rol tabanlı güvenlik konusunu inceleyeceğiz. Bunun için kendimize özel bir güvenlik yapısı oluşturacağız. Dynamic Data - Tablo ve kolon isimleri için globalizasyon işlemi başlıklı yazının okunmasında büyük fayda vardır. Bir çok yerde globalizasyon yapısında kullanılan yapının bilindiği kabul edilecektir. Yazı boyunca aşağıdaki iki tablo ile alakalı bilgiler yer alacaktır.

Dynamic data'yı yönetim paneli oluşturmak için kullandığımızı düşünelim. Tabiki aynı anda bir çok kullanıcı farklı güvenlik seviyeleriyle yönetim panelini kullanabilmelidir. Örneğin Admin seviyesindeki kullanıcı her şeyi yapabilirken editor seviyesinde bazı işllemler kısıtlanmalıdır. Bu kapsamda yapacağımız işi özetleyecek olursak; yetkilendirme işlemleri için bir xml dosyası hazırlayacağız ve MetaColumn sınıfından türettiğimiz yeni bir sınıf yardımıyla tablo ve kolonlar üzerindeki yetkileri kısıtlayacağız.Haydi kodlayalım.

Globalizasyon yazısındakine benzer şekilde xml dosyamız aşağıdaki gibi olsun:


<?xml version="1.0" encoding="utf-8" ?>
<permissions>
  <cruds>
    <crud name="Personel" operations="c,u,d" denyRoles="users" />   
  </cruds>
  <dbobjects>
    <dbobject name="Personel.Soyadi" denyRoles="users,editors" />
  </dbobjects>
</permissions>

cruds segmentinde ekleme(c), okuma(r), güncelleme(u) ve silme(d) işlemlerini kısıtlayacağımız tablolar yer alırken dbobjects segmentinde tablo kolonlarının kullanılabilirliğini kısıtlıyor olacağız. Örneğin bu xml dosyasına göre users ve editors grubları Personel tablosundaki Soyadi alanını hiç bir yerde göremeyecekler.

Şimdi xml dosyasını okuyup gerekli kısıtlamayı yapacak sınıfa gelelim.

PermissionsHelper.cs sınıfı kaynak kodları:

namespace DynLibrary.Helpers
{
    using System.Collections;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Data;
    using System.IO;
    using System.Web.Hosting;
    using System.Web.Security;

    public static class PermissionHelper
    {
        /// 
        /// Tüm kısıtlama tanımlamalarını saklayacak koleksiyon
        /// 
        private static Hashtable _permisssionList;

        static PermissionHelper()
        {
            _permisssionList = new Hashtable();

            // Kısıtlama tanımlamalarını yükle
            LoadPermission();
        }

        /// 
        /// Kısıtlama tanımlarını yükleyecek metot
        /// 
        private static void LoadPermission()
        {
            string configFolder = ConfigurationManager.AppSettings["DynamicDataConfigFolder"];
            string fullDbObjectsPath = Path.Combine(HostingEnvironment.MapPath(configFolder), "Permissions.xml");

            string gKey = string.Empty;
            DataSet ds = new DataSet();

            // Xml dosyası okunuyor
            ds.ReadXml(fullDbObjectsPath);

            #region dbobject

            if (ds.Tables["dbobject"].Rows.Count > 0)
            {
                List denyDboRolesList;
                foreach (DataRow row in ds.Tables["dbobject"].Rows)
                {
                    denyDboRolesList = new List();

                    // Tüm kısıtlamalar _permisssionList koleksiyonunda tutulacağından
                    // bu koleksiyona tanımlanacak anahtarların eşsiz olması gerekiyor.
                    // Koleksiyona atanacak anahtar tanımlanıyor.
                    gKey = string.Format("dbobjects.{0}.roles.deny", row["name"]);

                    // denyRoles özniteliğindeki roller virgülle ayırıldığından
                    // Split yardımıyla her biri tek tek denyDboRolesList
                    // koleksiyonuna aktarılıyor.
                    denyDboRolesList.AddRange(row["denyRoles"].ToString().Split(','));

                    // Eğer koleksiyonda böyle bir anahtar varsa üzerine yaz yoksa ekle
                    if (!_permisssionList.Contains(gKey))
                        _permisssionList.Add(gKey, denyDboRolesList);
                    else
                        _permisssionList[gKey] = denyDboRolesList;
                }
            }

            #endregion

            #region crud

            if (ds.Tables["crud"].Rows.Count > 0)
            {
                List denyCrudRolesList;

                foreach (DataRow row in ds.Tables["crud"].Rows)
                {
                    denyCrudRolesList = new List();

                    // denyRoles özniteliğindeki roller virgülle ayırıldığından
                    // Split yardımıyla her biri tek tek denyDboRolesList
                    // koleksiyonuna aktarılıyor.
                    denyCrudRolesList.AddRange(row["denyRoles"].ToString().Split(','));

                    foreach (string operation in row["operations"].ToString().Split(','))
                    {
                        // Tüm kısıtlamalar _permisssionList koleksiyonunda tutulacağından
                        // bu koleksiyona tanımlanacak anahtarların eşsiz olması gerekiyor.
                        // Koleksiyona atanacak anahtar tanımlanıyor.
                        gKey = string.Format("cruds.{0}.{1}.roles.deny", row["name"], operation);

                        // Eğer koleksiyonda böyle bir anahtar varsa üzerine yaz yoksa ekle
                        if (!_permisssionList.Contains(gKey))
                            _permisssionList.Add(gKey, denyCrudRolesList);
                        else
                            _permisssionList[gKey] = denyCrudRolesList;
                    }
                }


            }

            #endregion
        }

        /// 
        /// O anki kullanıcının dboObjectName değişkeninde bildirilen
        /// nesneye erişme durumunu dönderir
        /// 
        /// Erişmek istenilen nesne
        /// 
        public static bool CanAccessDboObject(string dboObjectName)
        {
            // Henüz rol tabanlı güvenlikle alakalı kod yazılmadığından
            // roleNames değişkenini el ile atıyorum. Roles.GetRolesForUser()
            // metotu ile daha sonra gerçek ortamda kullanılabilir.
            string[] roleNames = { "users" }; // TODO: Roles.GetRolesForUser();

            // Eşsiz anahtar oluşturuluyor
            string roleDenyKey = string.Format("dbobjects.{0}.roles.deny", dboObjectName);

            // Eğer herhangi bir kısıtlama varsa false değerini dönder
            // metotun en altında eğer hiç bir engele takılmamışsa
            // true değeri dönsün.
            //
            // Bu nesneye ait herhangi bir engelleme var mı?
            if (_permisssionList.Contains(roleDenyKey))
            {
                // Engellemeye ait rol tanımlamalarını getir.
                List denyList = (List)_permisssionList[roleDenyKey];

                // Kullanıcının rolü engellemede tanımlıysa false değeri dönder
                foreach (var roleName in roleNames)
                {
                    if (denyList.Contains(roleName))
                        return false;
                }
            }

            return true;
        }

        /// 
        /// O anki kullanıcının tableName değişkeninde bildirilen
        /// nesne üzerinde bildirilen crud yetkisine sahip olma durumunu dönderir
        /// 
        /// crud yetkisi öğrenilecek tablo adı
        /// 
        /// c:Create
        /// r=Read
        /// u=Update
        /// d=Delete
        /// 
        /// 
        public static bool CanAccessCrudOperation(string tableName, char crudOperation)
        {
            // Henüz rol tabanlı güvenlikle alakalı kod yazılmadığından
            // roleNames değişkenini el ile atıyorum. Roles.GetRolesForUser()
            // metotu ile daha sonra gerçek ortamda kullanılabilir.
            string[] roleNames = { "users" }; // TODO: Roles.GetRolesForUser();

            // Eşsiz anahtar oluşturuluyor
            string roleDenyKey = string.Format("cruds.{0}.{1}.roles.deny", tableName, crudOperation);

            // Eğer herhangi bir kısıtlama varsa false değerini dönder
            // metotun en altında eğer hiç bir engele takılmamışsa
            // true değeri dönsün.
            //
            // Bu tablo üzerinde ilgili crud işlemi için herhangi bir engelleme var mı?
            if (_permisssionList.Contains(roleDenyKey))
            {
                // Engellemeye ait rol tanımlamalarını getir.
                List denyList = (List)_permisssionList[roleDenyKey];

                // Kullanıcının rolü engellemede tanımlıysa false değeri dönder
                foreach (var roleName in roleNames)
                {
                    if (denyList.Contains(roleName))
                        return false;
                }
            }

            return true;
        }
    }
}

 

PermissionHelpers sınıfından sonra MetaModel, MetaTable ve MetaColumn sınıflarının işini yapacak sınıf tanımlamalarını yapalım.

DynMetaModel.cs dosyası kaynak kodları:

namespace DynLibrary.Entities
{
    using System.Web.DynamicData;
    using System.Web.DynamicData.ModelProviders;

    /// 
    /// MetaModel nesnesinden türetilen DynMetaModel nesnesi
    /// 
    public class DynMetaModel : MetaModel
    {
        public DynMetaModel()
            : base()
        {
        }

        /// 
        /// Tablo nesnesini oluşturan metottur. Bu metotta MetaTable yerine kendi
        /// nesnemiz olan ve MetaTable nesnesinden türemiş olan DynMetaTable
        /// nesnesini üretiyoruz.
        /// 
        /// 
        /// 
        protected override MetaTable CreateTable(TableProvider provider)
        {
            return new DynMetaTable(this, provider);
        }       
    }
}

 

DynMetaTable.cs dosyası kaynak kodları:

namespace DynLibrary.Entities
{
    using System.Web.DynamicData;
    using System.Web.DynamicData.ModelProviders;
    using DynLibrary.Helpers;

    /// 
    /// MetaTable nesnesinden türetilen DynMetaTable nesnesi
    /// 
    public class DynMetaTable : MetaTable
    {
        public DynMetaTable(MetaModel metaModel, TableProvider tableProvider)
            : base(metaModel, tableProvider)
        {}

        protected override void Initialize()
        { base.Initialize(); }

        /// 
        /// Kolon nesnesini oluşturan metottur. Bu metotta MetaColumn yerine kendi
        /// nesnemiz olan ve MetaColumn nesnesinden türemiş olan DynMetaColumn
        /// nesnesini üretiyoruz.
        /// 
        /// 
        /// 
        protected override MetaColumn CreateColumn(ColumnProvider columnProvider)
        {
            return new DynMetaColumn(this, columnProvider);
        }
    }
}

 

DynMetaColumn.cs dosyası kaynak kodları:

namespace DynLibrary.Entities
{
    using System.Web.DynamicData;
    using System.Web.DynamicData.ModelProviders;
    using DynLibrary.Helpers;
    using System.Web.Security;

    public class DynMetaColumn : MetaColumn
    {
        public DynMetaColumn(MetaTable metaTable, ColumnProvider columnProvider)
            : base(metaTable, columnProvider)
        { }

        public override bool Scaffold
        {
            get
            {
                //if (base.Scaffold)
                //    return true;
                return PermissionHelper.CanAccessDboObject(this.Table.EntityType.Name + "." + this.Name);
            }
        }
    }
}

 

DynMetaColumn sınıfında ezilen Scaffold özelliğini tabloya yazılan ek sınıflar(partial) ile her bir alan için tek tek tanımlamamız gerekiyordu. Burada ise her kolon oluşturulurken bu özellik çağırılacağından, tüm çağırma işlemlerini denetleme şansımız oluyor. Şimdi sıra son kod değişikliğinde, Global.asax dosyasında oluşturduğumuz MetaModel'i kullan dediğimizde işlem tamamlanmış olacaktır. Sayfa şablonlarından da ilgili değişiklikleri kontrol etmemiz gerekiyor. Bunun gerekli kodları tek tek yayınlamak yerine tüm projeyi(globalizasyon desteği de dahil olmak üzere) konunun en altındaki linkten indirebilirsiniz.

 

// Eski hali: MetaModel model = new MetaModel();
DynMetaModel model = new DynMetaModel();

 

Yetki kontrolü öncesi Personel tablosu görünümü:



 

Yetki kontrolü sonrası Personel tablosu görünümü:



 

 

Örnek projeyi indirmek için:
DD_Permissons_Globalization.rar (316,78 kb)

 

Faydalı olması dileğiyle, mutlu kodlar!
Ömer Faruk ZORLU

Kahve ısmarlayın

Aşağıdaki kahve simgesine tıklayarak bana paypal üzerinden kahve ısmarlayabilirsiniz. Kahveye olan düşkünlüğü ile bilinen birisi olarak büyük bir zevkle içeceğimden emin olabilirsiniz.


Add comment




biuquote
Loading