مدیریت Session و Cookie در ASP.NET Core: راهنمای جامع
این ویژگی برای سادگی و مقیاسپذیری وب عالی است، اما یک مشکل اساسی برای برنامههای کاربردی مدرن ایجاد میکند. چگونه میتوانیم «مرا به خاطر بسپار»، «سبد خرید» یا حتی وضعیت «وارد شده» (Logged In) کاربر را مدیریت کنیم؟ اگر سرور هر بار ما را فراموش کند، تجربه کاربری مختل خواهد شد.
اینجاست که دو مفهوم کلیدی وارد میشوند: کوکیها (Cookies) و نشستها (Sessions). این دو، مکانیزمهای اصلی برای غلبه بر بیحالتی HTTP و ایجاد یک تجربه کاربری پیوسته هستند. ASP.NET Core، به عنوان یک فریمورک مدرن و قدرتمند، ابزارهای انعطافپذیر و امنی برای مدیریت هر دوی این موارد ارائه میدهد. در این مقاله، به کاوش عمیق نحوه مدیریت کوکیها و سشنها در ASP.NET Core خواهیم پرداخت.
بخش اول: کوکیها (Cookies) - حافظه در سمت کلاینت
کوکیها قطعات کوچکی از داده (متن) هستند که سرور به مرورگر کاربر ارسال میکند. مرورگر این دادهها را ذخیره کرده و در هر درخواست بعدی به همان سرور، آنها را بازمیگرداند. کوکیها ستون فقرات بسیاری از قابلیتهای وب هستند.
کوکی چیست و چگونه کار میکند؟
-
ایجاد (Server -> Client): زمانی که کاربر به یک وبسایت مراجعه میکند، سرور میتواند یک کوکی را از طریق هدر HTTP Set-Cookie در پاسخ (Response) خود قرار دهد.
-
ذخیره (Client): مرورگر کاربر این کوکی را دریافت و بر اساس پارامترهای آن (مانند دامنه و مسیر) ذخیره میکند.
-
ارسال مجدد (Client -> Server): در هر درخواست بعدی به همان دامنه، مرورگر به طور خودکار کوکی(های) ذخیره شده را در هدر HTTP Cookie به سرور ارسال میکند.
ویژگیهای کلیدی یک کوکی (Attributes)
هنگام تنظیم یک کوکی، فقط نام و مقدار آن مهم نیست، بلکه "فرا-داده" (Metadata) آن نیز حیاتی است:
-
Expires / Max-Age: تعیین میکند کوکی تا چه زمانی معتبر است. Expires یک تاریخ و زمان مشخص است، در حالی که Max-Age مدت زمان اعتبار را به ثانیه مشخص میکند. اگر هیچکدام تنظیم نشوند، کوکی به عنوان کوکی نشست (Session Cookie) در نظر گرفته شده و با بسته شدن مرورگر از بین میرود.
-
Domain / Path: مشخص میکند که کوکی باید برای کدام دامنهها و مسیرها ارسال شود. این یک مکانیزم امنیتی برای جلوگیری از ارسال کوکی به سرورهای نامرتبط است.
-
Secure: اگر این پرچم (Flag) تنظیم شود، مرورگر کوکی را فقط از طریق اتصالات امن HTTPS ارسال میکند.
-
HttpOnly: این یکی از مهمترین ویژگیهای امنیتی است. کوکیهای HttpOnly از طریق جاوا اسکریپت سمت کلاینت (document.cookie) قابل دسترسی نیستند. این کار به شدت به جلوگیری از حملات XSS (Cross-Site Scripting) کمک میکند، زیرا اسکریپتهای مخرب نمیتوانند کوکیهای حساس (مانند کوکی احراز هویت) را سرقت کنند.
-
SameSite: این ویژگی امنیتی جدیدتر، برای مقابله با حملات CSRF (Cross-Site Request Forgery) طراحی شده است. این ویژگی کنترل میکند که آیا کوکی باید در درخواستهایی که از دامنههای دیگر نشأت میگیرند (Cross-Site) ارسال شود یا خیر.
-
Strict: کوکی فقط در صورتی ارسال میشود که درخواست از همان سایت مبدأ باشد.
-
Lax: (مقدار پیشفرض در مرورگرهای مدرن) کوکی در ناوبریهای سطح بالا (مانند کلیک روی یک لینک) ارسال میشود، اما در درخواستهای پسزمینه (مانند fetch یا فرمهای POST) از سایت دیگر، ارسال نمیشود.
-
None: کوکی در تمام درخواستهای بینسایتی ارسال میشود. این گزینه نیازمند پرچم Secure است.
-
مدیریت کوکیها در ASP.NET Core
کار با کوکیها در ASP.NET Core به طور شگفتآوری ساده است و مستقیماً از طریق HttpContext انجام میشود.
1. نوشتن (Append) یک کوکی:
برای ایجاد یا بهروزرسانی یک کوکی، از Response.Cookies.Append استفاده میکنیم.
[HttpGet("setcookie")]
public IActionResult SetCookie()
{
// تنظیمات کوکی
var cookieOptions = new CookieOptions
{
Expires = DateTime.Now.AddDays(7), // ماندگاری برای ۷ روز
HttpOnly = true, // عدم دسترسی جاوا اسکریپت
Secure = true, // فقط روی HTTPS
SameSite = SameSiteMode.Lax // محافظت در برابر CSRF
};
// اضافه کردن کوکی به پاسخ
Response.Cookies.Append("UserId", "12345", cookieOptions);
return Ok("کوکی با موفقیت تنظیم شد.");
}
2. خواندن (Read) یک کوکی:
برای خواندن کوکیهایی که کلاینت ارسال کرده است، از Request.Cookies استفاده میکنیم.
[HttpGet("readcookie")]
public IActionResult ReadCookie()
{
// تلاش برای خواندن کوکی
if (Request.Cookies.TryGetValue("UserId", out string userId))
{
return Ok($"مقدار کوکی UserId: {userId}");
}
return NotFound("کوکی مورد نظر یافت نشد.");
}
3. حذف (Delete) یک کوکی:
برای حذف یک کوکی، کافی است آن را با تاریخ انقضای گذشته Append کنیم. ASP.NET Core یک متد کمکی به نام Delete برای این کار فراهم کرده است.
[HttpGet("deletecookie")]
public IActionResult DeleteCookie()
{
// حذف کوکی با دادن نام آن
// (این متد در پشت صحنه همان تنظیم تاریخ انقضای گذشته را انجام میدهد)
Response.Cookies.Delete("UserId");
return Ok("کوکی حذف شد.");
}
بخش دوم: Session (نشست) - حافظه در سمت سرور
در حالی که کوکیها دادهها را در کلاینت ذخیره میکنند، Session دادهها را در سرور ذخیره میکند. این مکانیزم برای ذخیرهسازی دادههای موقت و مختص به یک کاربر (مانند سبد خرید یا اطلاعات پروفایل موقت) ایدهآل است.
Session چگونه کار میکند؟
-
ایجاد شناسه (Session ID): هنگامی که کاربر برای اولین بار با برنامه تعامل میکند (و سشن فعال میشود)، ASP.NET Core یک شناسه نشست (Session ID) منحصربهفرد تولید میکند.
-
ذخیره شناسه در کلاینت: این Session ID به عنوان یک کوکی به مرورگر کاربر ارسال میشود. (به طور پیشفرض، این یک کوکی HttpOnly و موقت به نام .AspNetCore.Session است).
-
ارتباط با سرور: در هر درخواست بعدی، مرورگر این کوکی Session ID را به سرور میفرستد.
-
بازیابی داده: سرور از این ID برای پیدا کردن و بارگذاری دادههای مرتبط با آن کاربر از حافظه سرور (یا کش توزیعشده) استفاده میکند.
مزیت کلیدی Session نسبت به Cookie: دادههای حساس (مانند محتویات سبد خرید یا شناسه کاربر در سرور) هرگز به کلاینت ارسال نمیشوند. تنها چیزی که کلاینت دارد، یک شناسه بیمعنی (Session ID) است. این امر امنیت را به طور قابل توجهی افزایش میدهد و محدودیت حجم کوکی (معمولاً 4KB) را نیز ندارد.
پیادهسازی و پیکربندی Session در ASP.NET Core
استفاده از Session در ASP.NET Core یک فرآیند دو مرحلهای است:
مرحله ۱: ثبت سرویسها (در Program.cs)
ابتدا باید به ASP.NET Core بگوییم که چگونه دادههای سشن را ذخیره کند. به طور پیشفرض، از یک کش توزیعشده در حافظه (In-Memory Distributed Cache) استفاده میشود.
// در فایل Program.cs (یا Startup.cs در نسخههای قدیمیتر)
var builder = WebApplication.CreateBuilder(args);
// ... سایر سرویسها مانند AddControllersWithViews ...
// ۱. اضافه کردن سرویس کش توزیعشده در حافظه
// (این سرویس برای نگهداری دادههای سشن ضروری است)
builder.Services.AddDistributedMemoryCache();
// ۲. اضافه کردن سرویس Session
builder.Services.AddSession(options =>
{
// تنظیم زمان وقفه (Timeout)
// اگر کاربر برای این مدت فعالیتی نداشته باشد، سشن منقضی میشود.
options.IdleTimeout = TimeSpan.FromMinutes(20);
// تنظیمات کوکی سشن
options.Cookie.Name = ".MyApp.Session"; // نام دلخواه برای کوکی
options.Cookie.HttpOnly = true; // همیشه HttpOnly باشد
options.Cookie.IsEssential = true; // برای سازگاری با GDPR (کوکی ضروری)
options.Cookie.SecurePolicy = CookieSecurePolicy.Always; // در پروداکشن همیشه Always باشد
});
// ...
مرحله ۲: فعالسازی میانافزار (Middleware)
پس از ساختن app، باید میانافزار UseSession را به خط لوله (Pipeline) درخواست اضافه کنیم.
نکته بسیار مهم در مورد ترتیب: app.UseSession() باید بعد از app.UseRouting() و قبل از app.MapControllerRoute() یا app.UseEndpoints() و app.UseAuthorization() فراخوانی شود.
// ...
var app = builder.Build();
// ... سایر میانافزارها ...
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
// ۳. فعالسازی میانافزار سشن
// (جایگاه آن در خط لوله اهمیت دارد)
app.UseSession();
app.UseAuthentication(); // اگر وجود دارد
app.UseAuthorization(); // اگر وجود دارد
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();

کار با دادهها در Session
پس از پیکربندی، میتوانیم به سشن از طریق HttpContext.Session در کنترلرها یا Razor Pages دسترسی داشته باشیم.
محدودیت: سشن در ASP.NET Core به طور پیشفرض فقط میتواند byte[] (آرایه بایت)، string و Int32 (اعداد صحیح) را ذخیره کند.
[ApiController]
[Route("[controller]")]
public class CartController : ControllerBase
{
[HttpGet("add")]
public IActionResult AddToCart(string
product)
{
// تنظیم یک مقدار رشتهای
HttpContext.Session.SetString("LastProduct", product);
// تنظیم یک مقدار عددی
int itemCount = (HttpContext.Session.GetInt32("ItemCount") ?? 0) + 1;
HttpContext.Session.SetInt32("ItemCount", itemCount);
return Ok($"محصول {product} اضافه شد. تعداد کل: {itemCount}");
}
[HttpGet("view")]
public IActionResult ViewCart()
{
string lastProduct = HttpContext.Session.GetString("LastProduct") ?? "خالی";
int itemCount = HttpContext.Session.GetInt32("ItemCount") ?? 0;
return Ok($"آخرین محصول: {lastProduct}, تعداد: {itemCount}");
}
[HttpGet("clear")]
public IActionResult ClearSession()
{
// پاک کردن کل دادههای سشن
HttpContext.Session.Clear();
return Ok("سشن پاک شد.");
}
}
ذخیره اشیاء پیچیده (Complex Objects) در Session:
برای ذخیره اشیائی مانند یک کلاس ShoppingCart، باید آن را به string (معمولاً JSON) سریالایز (Serialize) کنیم و هنگام خواندن، آن را دیسریالایز (Deserialize) کنیم.
میتوانیم متدهای کمکی (Extension Methods) برای این کار بنویسیم:
// یک فایل کمکی مانند SessionExtensions.cs
using System.Text.Json;
public static class SessionExtensions
{
public static void Set<T>(this ISession session, string key, T value)
{
session.SetString(key, JsonSerializer.Serialize(value));
}
public static T Get<T>(this ISession session, string key)
{
var value = session.GetString(key);
return value == null ? default : JsonSerializer.Deserialize<T>(value);
}
}
حالا میتوانیم به راحتی اشیاء را ذخیره کنیم:
public class ShoppingCart { public List<string> Items { get; set; } = new(); }
// ... در کنترلر ...
var cart = HttpContext.Session.Get<ShoppingCart>("Cart") ?? new ShoppingCart();
cart.Items.Add("Laptop");
HttpContext.Session.Set("Cart", cart); // ذخیره مجدد شیء کامل
بخش سوم: ذخیرهسازهای Session (Session Storage)
استفاده از AddDistributedMemoryCache() (همانطور که در مثال بالا دیدیم) برای توسعه و تست عالی است، اما یک مشکل بزرگ دارد: دادهها در حافظه همان سرور ذخیره میشوند.
این دو پیامد منفی دارد:
-
عدم ماندگاری: اگر برنامه ریاستارت شود (مثلاً هنگام انتشار نسخه جدید)، تمام سشنها از بین میروند.
-
عدم مقیاسپذیری (Load Balancing): اگر برنامه شما روی چندین سرور (مزرعه وب یا Web Farm) اجرا شود، درخواستهای کاربر ممکن است به سرورهای مختلفی ارسال شوند. اگر سشن کاربر در سرور A ایجاد شده باشد، سرور B به آن دسترسی نخواهد داشت و سشن "گم" میشود. (مگر اینکه از Sticky Sessions استفاده کنید که توصیه نمیشود).
راهحل، استفاده از یک کش توزیعشده (Distributed Cache) واقعی است که خارج از فرآیند برنامه شما قرار دارد.
1. SQL Server Distributed Cache:
میتوانید از یک دیتابیس SQL Server برای ذخیره دادههای سشن استفاده کنید. این گزینه پایدار و قابل اعتماد است.
-
ابتدا باید ابزار dotnet-sql-cache را نصب و جدول مورد نیاز را در دیتابیس خود ایجاد کنید: dotnet tool install --global dotnet-sql-cache dotnet sql-cache create "Your_Connection_String" dbo SessionCache
-
سپس در Program.cs سرویس را جایگزین کنید:
// به جای AddDistributedMemoryCache() builder.Services.AddDistributedSqlServerCache(options => { options.ConnectionString = builder.Configuration.GetConnectionString("DefaultConnection"); options.SchemaName = "dbo"; options.TableName = "SessionCache"; }); builder.Services.AddSession(options => { /* ... */ });
2. Redis Distributed Cache (گزینه پیشنهادی برای کارایی بالا):
Redis یک پایگاه داده NoSQL بسیار سریع و مبتنی بر حافظه (In-Memory) است که برای کشینگ ایدهآل است. این گزینه بهترین عملکرد را برای مدیریت سشن در مقیاس بزرگ ارائه میدهد.
-
ابتدا پکیج Microsoft.Extensions.Caching.StackExchangeRedis را نصب کنید.
-
سپس سرویس را پیکربندی کنید:
// به جای AddDistributedMemoryCache() builder.Services.AddStackExchangeRedisCache(options => { options.Configuration = builder.Configuration.GetConnectionString("Redis"); options.InstanceName = "MyApp_"; // یک پیشوند برای کلیدها }); builder.Services.AddSession(options => { /* ... */ });
بخش چهارم: ملاحظات امنیتی و بهترین شیوهها
-
همیشه از HttpOnly استفاده کنید: چه برای کوکیهای سفارشی و چه برای کوکی سشن، HttpOnly = true حیاتیترین سپر دفاعی شما در برابر سرقت کوکی از طریق حملات XSS است.
-
همیشه از Secure در محیط پروداکشن استفاده کنید: Secure = true تضمین میکند که کوکیها فقط روی HTTPS منتقل میشوند و از حملات "مرد میانی" (Man-in-the-Middle) که ترافیک را شنود میکنند، جلوگیری میکند.
-
از SameSite غافل نشوید: SameSite = Lax یا Strict را به عنوان پیشفرض در نظر بگیرید تا از حملات CSRF جلوگیری کنید.
-
دادههای حساس را در کوکی ذخیره نکنید: هرگز رمز عبور، اطلاعات کارت اعتباری یا هر داده حساس دیگری را مستقیماً در کوکی ذخیره نکنید. کوکیها در دستگاه کاربر ذخیره میشوند و قابل بازرسی (و سرقت فیزیکی) هستند.
-
در سشن، دادههای عظیم ذخیره نکنید: به یاد داشته باشید که دادههای سشن در هر درخواست باید از کش (مثلاً Redis) خوانده (Deserialize) و در پایان درخواست نوشته (Serialize) شوند. ذخیره اشیاء بسیار بزرگ میتواند بر عملکرد سرور تأثیر منفی بگذارد. فقط دادههای ضروری را نگه دارید.
-
GDPR و رضایت کاربر (Cookie Consent): در بسیاری از نقاط جهان (مانند اروپا با GDPR)، شما موظف هستید قبل از ذخیره کوکیهای غیرضروری (مانند کوکیهای ردیابی یا تبلیغاتی) از کاربر رضایت بگیرید. ASP.NET Core دارای مکانیزم داخلی برای مدیریت رضایت کوکی است (ITrackingConsentFeature) که میتواند به طور خودکار تنظیم کوکیها را تا زمان پذیرش کاربر به تعویق بیندازد. (کوکی سشن و کوکی احراز هویت معمولاً "ضروری" یا IsEssential = true در نظر گرفته میشوند).
نتیجهگیری
کوکیها و سشنها دو ابزار بنیادی برای ساختن برنامههای وب پویا و کاربرپسند در دنیای بیحالت HTTP هستند. کوکیها به عنوان حافظه کوچک و ماندگار در سمت کلاینت عمل میکنند، در حالی که سشنها حافظه موقت و امنتری را در سمت سرور فراهم میآورند.
ASP.NET Core با ارائه یک API ساده برای مدیریت کوکیها (Request.Cookies و Response.Cookies) و یک سیستم مدیریت سشن انعطافپذیر و قابل توسعه (که توسط میانافزار UseSession و سرویسهای IDistributedCache پشتیبانی میشود)، به توسعهدهندگان قدرت میدهد تا به راحتی و با امنیت بالا، وضعیت کاربران خود را مدیریت کنند. درک عمیق ویژگیهای امنیتی مانند HttpOnly، Secure و SameSite و همچنین انتخاب ذخیرهساز مناسب برای سشن (مانند Redis) برای ساخت برنامههای وب قوی، مقیاسپذیر و امن، امری ضروری است.
0 نظر
هنوز نظری برای این مقاله ثبت نشده است.