صحبت کردیم ، در ادامه مقاله میخواهیم در مورد SPUserToken و Win32
API صحبت کنیم .
استفاده از User Token
یکی دیگر از راه های تغییر هویت در شیرپوینت استفاده از آبجکت SPUserToken می باشد .
با استفاده از این آبجکت کافیست شخص مورد نظر که میخواهیم عملیات با هویت او
اجرا شود را بدانیم و با به دست آوردن Token عملیات را اجرا
کنیم . با استفاده از مشخصه UserToken از کلاس
SPUser میتوانیم Token یک
شخص را بدست بیاوریم و سپس در Constructor کلاس
SPSite از آن استفاده کرده تا بتوانیم کدهای مورد نظر را اجرا کنیم .
این روش بهترین روش برای تغییر هویت می باشد ولی باید در هنگام استفاده از این
روش مطمئن باشید که کاربری که قصد انجام عملیات با هویت وی را دارید در سایت وجود
داشته باشد و همچنین مطمئن باشید که وی تمام دسترسی های لازم برای انجام عملیات
شما را دارد .
به مثال زیر توجه کنید :
SPWeb oWeb = SPContext.Current.Web;
SPUserToken token = oWeb.AllUsers[@"RaminAhmadi"].UserToken;
using (SPSite elevatedSite = new SPSite(oWeb.Site.ID, token))
{
using (SPWeb elevatedweb =
site.OpenWeb())
{
// codes
}
}
در این مثال زمانی که کاربری درخواستی را صادر میکند ، کدها با هویت RaminAhmadi اجرا می شوند ،
در واقع پس از ایجاد کلاس SPSite کلاس SPUser و SPUserTokenنیز
ایجاد می گردد و تمام منابعی که در داخل شیرپوینت فراخوانی شوند با دسترسی های این
کاربر خواهد بود .
اما نکاتی که در مورد این روش باید به آن توجه کنید :
Windows Security Context تغییر نمیکند !
در مثال بالا مقدار WindowsIdentity.GetCurrent().Name برابر SPContext.Current.Web.CurrentUser خواهد بود ، در
واقع هویت Windows Security Context تغییری نخواهد
کرد و برابر کاربری است که در شیرپوینت لاگین کرده است و درخواست را صادر نموده .
پس تمام دسترسی هایی که به منایع خارجی از جمله وب سرویس یا دیتابیس انجام شود
برابر هویت ویندوز کاربر جاری خواهد بود !
Token ها
محدودیت زمانی دارند !
شما فقط ۲۴ ساعت مهلت دارید تا از یک Token استفاده کنید ، حتما میپرسید خوب معمولا اکثر
عملیات در زمان های کوتاهی انجام می شود . باید خدمت شما عرض کنم که همیشه اینطور
نیست ، در صورتی که Workflow یا Event Receiver ( از نوع asynchronous ) داشته باشید
ممکن است زمان زیادی تا انجام گام بعدی وقفه وجود داشته باشد و در صورتی که Token در این مدت
انقضا شده باشد کد شما با هویت کاربر جاری اجرا خواهد شد .
اما نگران نباشید ، این مورد قابل تغییر است ، شما میتوانید با یک خط دستور در
PowerShell این موضوع را حل کنید :
stsadm -o setproperty
-propertyname token-timeout -propertyvalue 720
در مثال بالا ما زمان انقضا Token را
از ۲۴ ساعت به ۷۲ ساعت تغییر دادیم .
استفاده از Win32 API
همانطور که در روش های قبلی متوجه شده اید ما در هیچ یک از روش های قبلی نمیتوانیم
خارج از شیرپوینت هویت را تغییر دهیم ( مثل Console
Application ) .
اگر شما از پروژه های Console Application یا Windows
Application استفاده کنید و نیاز به تغییر هویت برای فراخوانی وب سرویس و یا
آبجکت مدل داشته باشید ، می بایست یک آبجکت از نوع WindowsIdentity ایجاد کنید :
class Program
{
//
Declare signatures for Win32 LogonUser and CloseHandle APIs
[DllImport("advapi32.dll", SetLastError = true)]
static extern bool LogonUser(
string principal,
string authority,
string password,
LogonSessionType logonType,
LogonProvider logonProvider,
out IntPtr token);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr handle);
enum LogonSessionType : uint
{
Interactive = 2,
Network,
Batch,
Service,
NetworkCleartext = 8,
NewCredentials
}
enum LogonProvider : uint
{
Default = 0, // default for platform (use this!)
WinNT35, // sends smoke signals to authority
WinNT40, // uses NTLM
WinNT50 // negotiates Kerb or NTLM
}
static void Main(string[] args)
{
string username;
string password;
string domain;
Console.Write("Enter
username:");
username = Console.ReadLine();
Console.Write("Enter
domain:");
domain = Console.ReadLine();
Console.Write("Enter
password: ");
password = Console.ReadLine();
IntPtr token = IntPtr.Zero;
WindowsImpersonationContext impersonatedUser = null;
try
{
bool result = LogonUser(username, domain, password, LogonSessionType.Network,
LogonProvider.Default, out token);
if (result)
{
WindowsIdentity id = new WindowsIdentity(token);
// Begin impersonation
impersonatedUser =
id.Impersonate();
Console.WriteLine("Identity after impersonation : " + WindowsIdentity.GetCurrent().Name);
// Call to Sharepoint Web services or object model
}
else
{
Console.WriteLine("LogonUser failed: " + Marshal.GetLastWin32Error().ToString());
}
}
catch
{
}
finally
{
//
Stop impersonation and revert to the process identity
if (impersonatedUser != null)
impersonatedUser.Undo();
//
Free the token
if (token != IntPtr.Zero)
CloseHandle(token);
}
//
Verify the old process identity
Console.WriteLine(String.Format("Identity
after Undo: " + WindowsIdentity.GetCurrent().Name));
Console.Read();
}
}
روش های دیگری هم برای این کار وجود دارد مثل RevertToSelf (به
این
لینک مراجعه نمایید ) و Impersonate(intPtr) ( مثال زیر ) :
private void ImpersonateCodeExecution()
{
WindowsImpersonationContext ctx = null;
try
{
if (!WindowsIdentity.GetCurrent().IsSystem)
{
ctx = WindowsIdentity.Impersonate(System.IntPtr.Zero);
//execute your code here
}
}
catch { }
finally
{
if (ctx != null)
{
ctx.Undo();
}
}
}
نکات مهم در مورد Impersonation در شیرپوینت :
·
سعی کنید به جای
استفاده از SPSecurity.RunWithElevatedPrivileges از SPUserToken در کدهای خود
استفاده کنید ، تنها در صورتی که نیاز به فراخوانی های خارج از شیرپوینت دارید که
می بایست تحت اکانت Application Pool Identity اجرا شوند یا SPUser معتبر و یا
شناخته شده ای برای انجام عملیات خود ندارید از SPSecurity.RunWithElevatedPrivileges استفاده کنید .
·
در صورتی که از SPSecurity.RunWithElevatedPrivileges استفاده می
کنید همیشه تمام آبجکت های داخل بلاک را Dispose نمایید و آن ها
را به خارج از بلاک منتقل نکنید .
·
در صورتی که در
خارج از شیرپوینت نیاز به تغییر هویت دارید از Win32 API و یا WindowsIdentity.Impersonate(token) استفاده نمایید
.
و اما در پایان لینک های مفید درباره Impersonation در شیرپوینت :
How To: Use
Impersonation and Delegation in ASP.NET
موفق و پیروز باشید.