باشد ، اما گاهی این مسئله مشکلات بسیاری همراه خود دارد و در صورتی که به درستی
استفاده نشود خواسته های شما را برآورده نخواهد کرد.
امروز میخوام این مسئله رو به صورت کامل برای شما باز کنم ، اما قبل از اینکه
به سراغ موارد استفاده بریم شرح کوتاهی در مورد Impersonation خواهیم داد :
Impersonation به نحوه پردازش کد یا بخشی از کد با هویت یک
شخص دیگر در Context گفته می شود.
در برخی موارد ممکن است شما بخواهید از هویت شخصی دیگر ، هویت Application
Pool ، مدیر سایت یا مجموعه سایت ( System Account ) و یا حتی از
هویت کاربران ویندوز به خاطر مجوزهایی که هر یکی از این افراد دارند استفاده کنید
، اما قبل از اینکه تصمیم بگیرید که از برای Impersonation از چه هویتی استفاده کنید این نکته بسیار مهم
است که تفاوت بین SharePoint Security Context و Windows
Security Context را خوب درک کنید .
در محیط شیرپوینت و برنامه هایی که برای آن نوشته می شود (مثل یک وب پارت )
شما علاوه بر اینکه نیاز دارید به منابع داخلی دسترسی داشته باشید ( مانند لیست ها
، مخازن اسناد ، فایل ها و … ) ممکن است نیاز به دسترسی به منابع خارجی پیدا
کنید ( مانند جداولی در SQL Server یا
یک سیستم خارجی و یا حتی Shared Folders ) که دسترسی به این منابع خارج از کنترل
شیرپوینت می باشد ، پس زمانی که میخواهید از Impersonation استفاده کنید حتما باید این نکات را در نظر
داشته باشید تا تمام نیازهای شما برطرف گردد .
خوب حالا اجازه بدید ببینیم چطور میتونیم از روش های مختلف برای Impersonation
استفاده کنیم :
استفاده از SPSecurity.RunWithElevatedPrivileges
اجرای کدها توسط RunWithElevatedPrivileges یکی از محبوب
ترین روش ها برای اجرای کد با هویتی که دارای مجوزهای لازم است می باشد :
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite elevatedSite = new
SPSite(SPContext.Current.Site.Id))
{
using (SPWeb elevatedWeb =
elevatedSite.OpenWeb(SPContext.Current.Web.Id))
{
// codes …
}
}
});
اما با اجرای کدهایی که داخل این بلاک قرار میگیرند تغییراتی بدین صورت اعمال
خواهد شد :
هر دوی Windows Security Context و SharePoint
Security Context تغییر خواهند کرد .
elevatedWeb.CurrentUser.LoginName برابر SharePointSystem خواهد بود .
WindowsIdentity.getCurrent().Name برابر هویت Application Pool
خواهد بود.
با توجه به تغییراتی که صورت میگیرد کدهای داخل این بلاک بر مبنای هویت Application
Pool اجرا می شوند ( Windows Account ) که در واقع این هویت اجرا کننده Web
Application شماست و همچنین وظیفه پیکربندی تنظیمات دیتابیس را نیز بر عهده
دارد ، بنابراین با اجرای این کد شما به تمام منابع خارجی شامل Local
file System و جداول SQL Server دسترسی دارید .
همچنین با توجه به اینکه در حوزه SharePoint Security Context این کد با هویت
SHAREPOINTSYSTEM اجرا میشود ، هرگونه تغییری که بر روی آبجکت
ها اعمال شوند ( SPFile ، SPListItem ، SPWeb و … )
تغییرات با هویت SHAREPOINTSYSTEM ثبت می شوند ( Created
By و Modified By ) .
اما نکات مهمی در مورد RunWithElevatedPrivileges هستند که باید
در مورد آنها اطلاعات کافی داشته باشیم :
۱ – RunWithElevatedPrivileges تنها زمانی اجرا می شود که آبجکت SPSite داخل این بلاک
ایجاد شود
شما می بایست برای اجرای کدها حتما آبکجت های SPSite و SPWeb را داخل بلاک
ایجاد نمایید ( با استفاده از Url ، ID سایت و یا حتی با استفاده از SPContext ) در غیر
اینصورت با خطای Access Denied مواجه خواهید شد ، به مثال زیر توجه کنید :
SPSecurity.RunWithElevatedPrivileges(delegate()
{
SPSite elevatedSite =
SPContext.Current.Site;
using (SPWeb elevatedWeb =
elevatedSite.OpenWeb())
{
// Performing administrative
actions here will give Access Denied exception.
}
}
});
فراموش نکنید که پس از استفاده از این آبجکت ها حتما آن ها را Dispose کنید .
۲- استفاده نادرست از آبجکت ها ممکن
است ریسک های امنیتی دربر داشته باشد
آبجکت هایی که در داخل این بلاک استفاده می شوند ( مانند SPFile ، SPList و … )
مجوزهای خود را حتی خارج از این بلاک نیز حفظ میکنند ! بنابراین شما نباید این
آبجکت ها را به خارج از بلاک ارسال کنید وگرنه ممکن است با مشکلات امنیتی مواجه
شوید . مثال زیر را در نظر بگیرید :
SPList taskList=null;
SPSecurity.RunWithElevatedPrivileges(delegate()
{
SPSite elevatedSite = SPContext.Current.Site;
using (SPWeb elevatedWeb =
elevatedSite.OpenWeb())
{
taskList =
elevatedWeb.Lists["Tasks"]
}
}
});
//This code will succeed even outside the block as it is accessed via
elevated SPWeb. Hence Security Risk.
taskList.Delete();
در واقع زمانی که شما یک آبجکت SPSite ایجاد میکنید ، این آّبجکت با زیر ساخت SPRequest ادامه پیدا
میکند و SPRequest کاربری که این آبجکت را ایجاد کرده به خاطر
میسپارد ، بنابراین تمام اشیایی که از SPSite مورد دسترسی قرار میگیرند SPRequest را مورد اشتراک
قرار می دهند .
در مثال بالا وقتی SPSite در این بلاک ایجاد میشود SPRequest کاربری
که این آبجکت را ایجاد کرده ثبت میکند که در مثال بالا SHAREPOINTSystem
می باشد . بنابراین زمانی
که آبجکتی مثل SPList را از این SPSite فراخوانی کنید
( مثل Site.RootWeb.Lists[ “Tasks”] ) ، این آبجکت حتی در خارج از بلاک نیز از
هویت SHAREPOINTSystem برای تغییرات بهره خواهد برد .
۳ – RunWithElevatedPrivileges تغییرات Windows Security Context را نیز به خوبی تشخیص می دهد .
به طور مثال اگر هویت Application Pool یک Web Application را از SPAdmin1 به SPAdmin2 تغییر دهید و
سپس از این بلاک استفاده کنید :
·
در داخل شیرپوینت
هویت همچنان SHAREPOINTSYSTEM خواهد بود ( SharePoint
Security Context)
·
تغییرات خارج از
شیرپوینت با هویت کاربر تغییر یافته ( SPAdmin2) اعمال خواهد
شد ( Windows Security Context )
بنابراین تمام درخواست هایی که به سیستم های خارجی صورت پذیرد ( مثل وب سرویس
یا دیتابیس ) بر اساس هویت Windows Account خواهد بود که با توجه به مجوزهای کاربر ممکن است
با موفقیت انجام شده و یا با خطا به پایان برسد.
۴- RunWithElevatedPrivileges زمانی که HTTPContext برابر Null باشد اجرا
نخواهد شد !
شما نمیتوانید از این بلاک زمانی که HTTPContext یا درواقع SPContext برابر Null باشد استفاده
کنید و کدهای داخل بلاک بدون توجه به RunWithElevatedPrivileges اجرا خواهند شد
، بنابراین شما نمیتوانید از این بلاک در پروژه های Console
Application ، Timer Job و حتی Event
Handlers که HTTPContext برابر Null می باشد ( به دلیل اینکه درخواستی از سمت مرورگر
ارسال نمیشود ) استفاده کنید .
۵ – RunWithElevatedPrivileges در پروژه های Sandbox solution اجرا نمیشود .
شما نمیتوانید از این بلاک در پروژه های sandbox solution استفاده کنید و
می بایست پروژه های شما حتما از نوع Farm Solution باشند . ( برای اطلاعات بیشتر در مورد محدودیت
های sandbox solution به این
لینک مراجعه کنید )
۶- اعمال تغییرات با هویت کاربر فعلی ( شخصی که عملیات را انجام میدهد )
همانطور که در بالا ذکر شد زمانی که شما از این بلاک
استفاده میکنید تمام تغییرات مانند Created
by و Modified by با هویت SHAREPOINTSYSTEM ذخیره خواهند شد ، ولی
مشکلی که اکثر توسعه دهندگان دارند در این است که میخواهند تغییرات با هویت شخص
جاری که در حال اجرای عملیات است ذخیره شود ( به عنوان مثل user1 ) .
برای این کار کافیست کاربر جاری را قبل از انجام عملیات در
بلاک در متغیری ذخیره کرده و سپس تغییرات را به اسم وی ثبت کنید ، به مثال زیر
توجه کنید :
private void UpdateItem(SPList
RestrictedList, bool IsAnonymous)
{
SPUser
user =SPContext.CurrentWeb.CurrentUser;
Guid
siteID = RestrictedList.ParentWeb.Site.ID;
Guid
webID = RestrictedList.ParentWeb.ID;
Guid
listID = RestrictedList.ID;
SPSecurity.RunWithElevatedPrivileges(()
=>
{
using
(SPSite site = new SPSite(siteID))
{
using (SPWeb web = site.OpenWeb(webID))
{
web.AllowUnsafeUpdates = true;
SPList elevatedList = web.Lists[listID];
SPListItem item = elevatedList.Items.Add();
SPUser systemUser =
web.AllUsers[@"SHAREPOINT\system"];
SPFieldUserValue
currentUser = new SPFieldUserValue( item.ParentList.ParentWeb, user.ID,
user.Name);
if (!IsAnonymous)
{
item["Author"] = currentUser;
item["Editor"] = currentUser;
} else {
item["Author"] = systemUser;
item["Editor"] = systemUser;
}
item.Update();
}
}
}
);
}
}
در این مثال فیلدهای Author و Editor مشخص کننده
ایجاد کننده و ویرایش کننده آیتم هستند .
امیدوارم که این مقاله مفید بوده باشه ، در قسمت بعد مقاله
در مورد SPUserToken و Win32 API صحبت
خواهیم کرد.
موفق و پیروز باشید