کار با کوکیها در ASP.NET Core
نویسنده: وحید نصیری
تاریخ: ۱۳۹۵/۰۷/۱۹ ۲۰:۴۵
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Core1RtmEmptyTest.Controllers
{
public class TestCookiesController : Controller
{
public IActionResult Index()
{
this.Response.Cookies.Append("key", "value", new CookieOptions
{
HttpOnly = true,
Path = this.Request.PathBase.HasValue ? this.Request.PathBase.ToString() : "/",
Secure = this.Request.IsHttps
});
return Content("OK!");
}
}
}
Expires = DateTimeOffset.UtcNow.AddDays(2)
var value = this.Request.Cookies["key"];
public interface IRequestCookieCollection : IEnumerable<KeyValuePair<string, string>>, IEnumerable
{
string this[string key] { get; }
ICollection<string> Keys { get; }
bool ContainsKey(string key);
bool TryGetValue(string key, out string value);
} string cookieValue;
if (this.Request.Cookies.TryGetValue(key, out cookieValue))
{
// TODO: use the cookieValue
}
else
{
// this cookie doesn't exist.
} this.Response.Cookies.Delete("key");
public interface ISecureCookiesProvider
{
void Add(HttpContext context, string token, string value);
bool Contains(HttpContext context, string token);
string GetValue(HttpContext context, string token);
void Remove(HttpContext context, string token);
}
public class SecureCookiesProvider : ISecureCookiesProvider
{
private readonly IProtectionProvider _protectionProvider;
public SecureCookiesProvider(IProtectionProvider protectionProvider)
{
_protectionProvider = protectionProvider;
}
public void Add(HttpContext context, string token, string value)
{
value = _protectionProvider.Encrypt(value);
context.Response.Cookies.Append(token, value, getCookieOptions(context));
}
public bool Contains(HttpContext context, string token)
{
return context.Request.Cookies.ContainsKey(token);
}
public string GetValue(HttpContext context, string token)
{
string cookieValue;
if (!context.Request.Cookies.TryGetValue(token, out cookieValue))
{
return null;
}
return _protectionProvider.Decrypt(cookieValue);
}
public void Remove(HttpContext context, string token)
{
if (context.Request.Cookies.ContainsKey(token))
{
context.Response.Cookies.Delete(token);
}
}
/// <summary>
/// Expires at the end of the browser's session.
/// </summary>
private CookieOptions getCookieOptions(HttpContext context)
{
return new CookieOptions
{
HttpOnly = true,
Path = context.Request.PathBase.HasValue ? context.Request.PathBase.ToString() : "/",
Secure = context.Request.IsHttps
};
}
} public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.TryAddSingleton<IProtectionProvider, ProtectionProvider>();
services.TryAddSingleton<ISecureCookiesProvider, SecureCookiesProvider>(); یک نکتهی تکمیلی: در تنظیمات کوکیهای سایت جدید، SameSite به Strict تنظیم شده بود:
options.Cookie.SameSite = SameSiteMode.Strict;
این موضوع سبب شده بود که اگر کاربری در سایت لاگین کرده بود و ایمیلی را دریافت میکرد، پس از کلیک بر روی ایمیل دریافتی و ورود به سایت، اعتبارسنجی نشده تلقی میشد و برای مثال امکان ارسال پاسخی را نداشت؛ چون حالت Strict به این معنا است که کوکیهای سایت (منجمله کوکی اعتبارسنجی کاربر)، فقط به درخواستهای رسیدهی از طریق خود سایت، به صورت خودکار توسط مرورگرها ارسال میشوند و نه در حالتیکه یک redirect از سایت دیگری وجود داشته باشد. برای تعدیل این تنظیم میتوان از حالت Lax استفاده کرد:
options.Cookie.SameSite = SameSiteMode.Lax;
در اصل، حالت Lax با حالت Strict، تفاوت آنچنانی ندارد و هنوز هم کوکیها را فقط به درخواستهای رسیدهی از طریق دومین جاری ارسال میکند. اما در این حالت اگر redirect ای نیز به دومین برنامه، از نوع GET وجود داشته باشد، آنرا امن حساب کرده و کوکیهای برنامه را در اختیار آن درخواست قرار میدهد.
پ.ن.
برای دریافت کوکیهای جدید از نوع Lax، باید یکبار از برنامه خارج شوید و مجددا به آن وارد شوید تا کوکیهای جدید را دریافت کنید.
مورد مشابه دیگری که نیاز به تنظیم دارد، کوکیهای anti-forgery-token هستند. اینها هم به صورت خودکار به SameSiteMode.Strict تنظیم شدهاند و اگر از طریق ایمیل، به فرمی مرتبط در سایت هدایت شوید و ... فرم را ارسال کنید، فقط یک صفحهی سفید رنگ را با پیام خطای 400، مشاهده خواهید کرد که قابل سفارشی سازی هم نیست (و مطلقا هم از تمام فیلترهای سراسری خطایابی شما، رد نمیشود). هدایت به سایت (یعنی یک redirect از سایت ثالث)، با کوکیهای از نوع Strict همخوانی ندارد و مرورگر، آنها را به سمت سرور ارسال نمیکند. به همین جهت این درخواستهای اعتبارسنجی anti-forgery-token هم برگشت خواهند خورد. برای تعدیل آن میتوان به صورت زیر عمل کرد:
services.Configure<AntiforgeryOptions>(opts => { opts.Cookie.SameSite = SameSiteMode.Lax; });
سلام؛ آیا استفاده از IProtectionProvider جهت درج اطلاعات در بخش Payload یک JWT Token را پیشنهاد میکنید؟
این مطلب و نظرات آنرا مطالعه کنید.