ASP.NET Core: Quản lý phiên và trạng thái trong ASP.NET Core


Khóa học qua video:
Lập trình Python All C# Lập trình C Java SQL Server PHP HTML5-CSS3-JavaScript
Đăng ký Hội viên
Tất cả các video dành cho hội viên

HTTP là một giao thức không trạng thái. Theo mặc định, các yêu cầu HTTP là các thông báo độc lập không giữ lại các giá trị của người dùng. Bài viết này mô tả một số phương pháp để bảo toàn dữ liệu người dùng giữa các yêu cầu.

Quản lý trạng thái

Trạng thái có thể được lưu trữ bằng một số cách tiếp cận. Mỗi cách tiếp cận được mô tả sau trong bài viết này.

Phương pháp lưu trữ Cơ chế lưu trữ
Cooki Cookie HTTP. Có thể bao gồm dữ liệu được lưu trữ bằng mã ứng dụng phía máy chủ.
Session state Cookie HTTP và mã ứng dụng phía máy chủ
Tempdata Cookie HTTP hoặc phiên bản trạng thái
Query strings Truy vấn chuỗi HTTP
Hidden fields Các trường form HTTP
HttpContext.Items Ứng dụng mã phía máy chủ
Cache Ứng dụng mã phía máy chủ

SignalR/Blazor Server và quản lý trạng thái dựa trên ngữ cảnh HTTP

Ứng dụng SignalR không nên sử dụng trạng thái phiên bản và các phương pháp quản lý trạng thái khác dựa trên ngôn ngữ HTTP ổn định để lưu trữ thông tin. Ứng dụng SignalR có thể lưu trữ trạng thái mỗi kết nối trong Context.Items ở trung tâm. Để biết thêm thông tin và các phương pháp quản lý trạng thái thay thế cho ứng dụng Blazor Server, hãy xem trạng thái quản lý ASP.NET Core Blazor.

Cooki

Cookie lưu dữ liệu theo yêu cầu. Vì cookie được gửi cùng với mọi yêu cầu nên kích thước của chúng phải được duy trì ở mức tối thiểu. Lý tưởng nhất chỉ là một số nhận dạng được lưu trữ trong cookie với dữ liệu được ứng dụng lưu trữ. Hầu hết các trình duyệt giới hạn kích thước cookie ở mức 4096 byte. Chỉ có một số giới hạn cookie có sẵn cho mỗi miền.

Vì cookie có thể bị giả mạo nên chúng phải được ứng dụng xác thực. Người dùng có thể xóa cookie và hết hạn trên máy khách. Tuy nhiên, cookie nói chung là hình thức lưu dữ liệu lâu bền nhất trên máy khách.

Cookie thường được sử dụng để cá nhân hóa, trong đó nội dung được tùy chỉnh cho người dùng đã biết. Người dùng chỉ được xác định và không được xác thực trong hầu hết các trường hợp. Cookie có thể lưu trữ tên người dùng, tên tài khoản hoặc ID người dùng duy nhất, chẳng hạn như GUID. Cookie có thể được sử dụng để truy cập cài đặt được cá nhân hóa của người dùng, chẳng hạn như màu nền trang web mà họ yêu thích.

Xem Quy định bảo vệ dữ liệu chung của Liên minh châu Âu (GDPR) khi phát hành cookie và giải quyết các vấn đề về quyền riêng tư. Để biết thêm thông tin, hãy xem hỗ trợ Quy định bảo vệ dữ liệu chung (GDPR) trong ASP.NET Core.

Trạng thái phiên

Trạng thái phiên là một kịch bản ASP.NET Core để lưu trữ dữ liệu của người dùng trong khi người dùng duyệt một ứng dụng web trạng thái. Trạng thái phiên sử dụng một store do ứng dụng duy trì để duy trì dữ liệu theo yêu cầu từ ứng dụng khách. Phiên dữ liệu được hỗ trợ bởi bộ đệm và được coi là dữ liệu tạm thời. Trang web sẽ tiếp tục hoạt động mà không có phiên dữ liệu. Dữ liệu quan trọng của ứng dụng nên được lưu trữ trong cơ sở dữ liệu của người dùng và chỉ được lưu vào bộ đệm ẩn trong phiên làm việc để tối ưu hóa hiệu suất.

Phiên không được hỗ trợ trong các ứng dụng SignalR vì SignalR Hub có thể thực thi độc lập với ngữ cảnh HTTP. Ví dụ: điều này có thể xảy ra khi một yêu cầu long polling được mở bởi một hub vượt quá thời gian tồn tại của ngữ cảnh HTTP của yêu cầu.

ASP.NET Core duy trì trạng thái phiên bằng cách cung cấp cookie cho máy khách có chứa ID phiên. ID phiên cookie:

  • Được gửi đến ứng dụng với mỗi yêu cầu.
  • Được ứng dụng sử dụng để tìm nạp dữ liệu phiên.

Trạng thái phiên thể hiện các hành vi sau:

  • Cookie phiên dành riêng cho trình duyệt. Các phiên không được chia sẻ trên các trình duyệt.
  • Cookie phiên sẽ bị xóa khi phiên trình duyệt kết thúc.
  • Nếu một cookie được nhận cho một phiên đã hết hạn, một phiên mới sẽ được tạo sử dụng cùng một cookie phiên.
  • Phiên trống không được giữ lại. Phiên phải có ít nhất một giá trị được thiết lập để duy trì phiên qua các yêu cầu. Khi một phiên không được giữ lại, ID phiên mới sẽ được tạo cho mỗi yêu cầu mới.
  • Ứng dụng giữ lại một phiên trong một khoảng thời gian giới hạn sau yêu cầu cuối cùng. Ứng dụng đặt thời gian chờ của phiên hoặc sử dụng giá trị mặc định là 20 phút. Trạng thái phiên là lý tưởng để lưu trữ dữ liệu người dùng:
    • Đó là cụ thể cho một phiên cụ thể.
    • Trường hợp dữ liệu không yêu cầu lưu trữ vĩnh viễn trong các phiên.
  • Dữ liệu phiên bị xóa khi  triển khai ISession.Clear được gọi hoặc khi phiên hết hạn.
  • Không có cơ chế mặc định nào để thông báo cho mã ứng dụng rằng trình duyệt máy khách đã bị đóng hoặc khi cookie phiên bị xóa hoặc hết hạn trên máy khách.
  • Theo mặc định, cookie trạng thái phiên không được đánh dấu là cần thiết. Trạng thái phiên không hoạt động trừ khi khách truy cập trang web cho phép theo dõi. Để biết thêm thông tin, hãy xem hỗ trợ Quy định bảo vệ dữ liệu chung (GDPR) trong ASP.NET Core.
  • Lưu ý: Không có sự thay thế nào cho tính năng phiên không có cookie từ ASP.NET Framework vì tính năng này được coi là không an toàn và có thể dẫn đến các cuộc tấn công cố định phiên.

Cảnh báo

Không lưu trữ dữ liệu nhạy cảm ở trạng thái phiên. Người dùng có thể không đóng trình duyệt và xóa cookie phiên. Một số trình duyệt duy trì cookie phiên hợp lệ trên các cửa sổ trình duyệt. Một phiên có thể không bị hạn chế đối với một người dùng. Người dùng tiếp theo có thể tiếp tục duyệt ứng dụng với cùng một cookie phiên.

Nhà cung cấp bộ đệm trong bộ nhớ lưu trữ dữ liệu phiên trong bộ nhớ của máy chủ nơi ứng dụng cư trú. Trong một kịch bản trang trại máy chủ:

Định cấu hình trạng thái phiên

Gói Microsoft.AspNetCore.Session:

  • Được đưa vào ngầm định bởi framework.
  • Cung cấp middleware để quản lý trạng thái phiên.

Để kích hoạt middleware phiên thì Program.cs phải chứa:

Đoạn mã sau cho biết cách thiết lập nhà cung cấp phiên trong bộ nhớ với triển khai trong bộ nhớ mặc định là IDistributedCache:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddDistributedMemoryCache();

builder.Services.AddSession(options =>
{
    options.IdleTimeout = TimeSpan.FromSeconds(10);
    options.Cookie.HttpOnly = true;
    options.Cookie.IsEssential = true;
});

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.UseSession();

app.MapRazorPages();
app.MapDefaultControllerRoute();

app.Run();

Đoạn code trên đặt thời gian chờ ngắn để đơn giản hóa việc kiểm tra.

Thứ tự của middleware là quan trọng. Hãy gọi UseSession sau UseRouting và trước MapRazorPages và MapDefaultControllerRoute. Xem Đặt hàng middleware.

HttpContext.Session khả dụng sau khi trạng thái phiên được định cấu hình.

HttpContext.Session không thể truy cập trước khi UseSession được gọi.

Không thể tạo phiên mới với cookie phiên mới sau khi ứng dụng đã bắt đầu ghi vào luồng phản hồi. Ngoại lệ được ghi lại trong nhật ký máy chủ web và không hiển thị trong trình duyệt.

Tải trạng thái phiên không đồng bộ

Nhà cung cấp phiên mặc định trong ASP.NET Core chỉ tải các bản ghi phiên từ  kho lưu trữ sao lưu IDistributedCache bên dưới một cách không đồng bộ nếu  phương thức ISession.LoadAsync được gọi rõ ràng trước các phương thức TryGetValueSet hoặc Remove. Nếu LoadAsync không được gọi trước, thì bản ghi phiên cơ bản sẽ được tải đồng bộ, điều này có thể dẫn đến giảm hiệu suất trên quy mô lớn.

Để các ứng dụng thực thi mẫu này, hãy wrap các triển khai DistributedSessionStore và DistributedSession bằng các phiên bản mà đưa ra ngoại lệ nếu phương thức LoadAsync không được gọi trước  TryGetValueSet, hoặc Remove. Đăng ký các phiên bản được wrap trong vùng chứa dịch vụ.

Tùy chọn phiên

Để ghi đè giá trị mặc định của phiên, hãy sử dụng SessionOptions.

Tùy chọn Mô tả
Cookie Xác định cài đặt được sử dụng để tạo cookie. Tên mặc định là SessionDefaults.CookieName (.AspNetCore.Session). Đường dẫn mặc định là SessionDefaults.CookiePath (/). SameSite mặc định là SameSiteMode.Lax (1). HttpOnly mặc định là trueIsEssential mặc định là false.
IdleTimeout Cho IdleTimeout biết phiên có thể không hoạt động trong bao lâu trước khi nội dung của nó bị bỏ qua. Mỗi lần truy cập phiên sẽ đặt lại thời gian chờ. Cài đặt này chỉ áp dụng cho nội dung của phiên, không áp dụng cho cookie. Mặc định là 20 phút.
IOTimeout Lượng thời gian tối đa được phép để tải một phiên từ cửa hàng hoặc chuyển nó trở lại cửa hàng. Cài đặt này chỉ có thể áp dụng cho các hoạt động không đồng bộ. Thời gian chờ này có thể bị vô hiệu hóa bằng InfiniteTimeSpan. Mặc định là 1 phút.

Phiên sử dụng cookie để theo dõi và xác định các yêu cầu từ một trình duyệt. Theo mặc định, cookie này được đặt tên là .AspNetCore.Session và sử dụng đường dẫn là /. Bởi vì cookie mặc định không chỉ định tên miền, nên nó không được cung cấp cho tập lệnh phía máy khách trên trang (vì HttpOnly mặc định là true).

Để ghi đè giá trị mặc định của phiên cookie, hãy sử dụng SessionOptions:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddDistributedMemoryCache();

builder.Services.AddSession(options =>
{
    options.Cookie.Name = ".AdventureWorks.Session";
    options.IdleTimeout = TimeSpan.FromSeconds(10);
    options.Cookie.IsEssential = true;
});

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.UseSession();

app.MapRazorPages();
app.MapDefaultControllerRoute();

app.Run();

Ứng dụng sử dụng thuộc tính IdleTimeout để xác định thời gian một phiên có thể không hoạt động trước khi nội dung của nó trong bộ đệm của máy chủ bị bỏ qua. Thuộc tính này độc lập với việc hết hạn cookie. Mỗi yêu cầu truyền đến Phiên Middleware sẽ đặt lại thời gian chờ.

Trạng thái phiên không khóa. Nếu hai yêu cầu đồng thời cố gắng sửa đổi nội dung của một phiên, thì yêu cầu cuối cùng sẽ ghi đè yêu cầu đầu tiên. Session được triển khai dưới dạng phiên nhất quán, có nghĩa là tất cả nội dung được lưu trữ cùng nhau. Khi hai yêu cầu tìm cách sửa đổi các giá trị phiên khác nhau, yêu cầu cuối cùng có thể ghi đè các thay đổi phiên được thực hiện bởi yêu cầu đầu tiên.

Đặt và nhận giá trị phiên

Trạng thái phiên được truy cập từ lớp Razor Pages PageModel hoặc  lớp Controller MVC với HttpContext.Session. Thuộc tính này là một triển khai ISession.

Việc ISession triển khai cung cấp một số phương thức mở rộng để đặt và truy xuất các giá trị số nguyên và chuỗi. Các phương thức mở rộng nằm trong namespace Microsoft.AspNetCore.Http.

Phương pháp mở rộng ISession:

Ví dụ sau truy xuất giá trị phiên cho khóa IndexModel.SessionKeyName (_Name trong ứng dụng mẫu) trong trang Razor Pages:

@page
@using Microsoft.AspNetCore.Http
@model IndexModel

...

Name: @HttpContext.Session.GetString(IndexModel.SessionKeyName)

Ví dụ sau đây cho thấy cách đặt và nhận một số nguyên và một chuỗi:

public class IndexModel : PageModel
{
    public const string SessionKeyName = "_Name";
    public const string SessionKeyAge = "_Age";

    private readonly ILogger<IndexModel> _logger;

    public IndexModel(ILogger<IndexModel> logger)
    {
        _logger = logger;
    }

    public void OnGet()
    {
        if (string.IsNullOrEmpty(HttpContext.Session.GetString(SessionKeyName)))
        {
            HttpContext.Session.SetString(SessionKeyName, "The Doctor");
            HttpContext.Session.SetInt32(SessionKeyAge, 73);
        }
        var name = HttpContext.Session.GetString(SessionKeyName);
        var age = HttpContext.Session.GetInt32(SessionKeyAge).ToString();

        _logger.LogInformation("Session Name: {Name}", name);
        _logger.LogInformation("Session Age: {Age}", age);
    }
}

Đánh dấu sau hiển thị các giá trị phiên trên một Razor Page:

@page
@model PrivacyModel
@{
    ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>

<div class="text-center">
<p><b>Name:</b> @HttpContext.Session.GetString("_Name");<b>Age:

</b> @HttpContext.Session.GetInt32("_Age").ToString()</p>
</div>

Tất cả dữ liệu phiên phải được tuần tự hóa để kích hoạt kịch bản bộ nhớ đệm phân tán, ngay cả khi sử dụng bộ nhớ đệm trong bộ nhớ. Các bộ nối tiếp chuỗi và số nguyên được cung cấp bởi các phương thức mở rộng của ISession. Các kiểu phức tạp phải được người dùng sắp xếp theo thứ tự bằng cơ chế khác, chẳng hạn như JSON.

Sử dụng code mẫu sau để tuần tự hóa các đối tượng:

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);
    }
}

Ví dụ sau đây cho thấy cách thiết lập và nhận một đối tượng có thể tuần tự hóa với lớp SessionExtensions:

using Microsoft.AspNetCore.Mvc.RazorPages;
using Web.Extensions;    // SessionExtensions

namespace SessionSample.Pages
{
    public class Index6Model : PageModel
    {
        const string SessionKeyTime = "_Time";
        public string? SessionInfo_SessionTime { get; private set; }
        private readonly ILogger<Index6Model> _logger;

        public Index6Model(ILogger<Index6Model> logger)
        {
            _logger = logger;
        }

        public void OnGet()
        {
            var currentTime = DateTime.Now;

            // Requires SessionExtensions from sample.
            if (HttpContext.Session.Get<DateTime>(SessionKeyTime) == default)
            {
                HttpContext.Session.Set<DateTime>(SessionKeyTime, currentTime);
            }
            _logger.LogInformation("Current Time: {Time}", currentTime);
            _logger.LogInformation("Session Time: {Time}", 
                           HttpContext.Session.Get<DateTime>(SessionKeyTime));

        }
    }
}

Cảnh báo

Việc lưu trữ một đối tượng trực tiếp trong phiên nên được sử dụng một cách thận trọng, vì có nhiều vấn đề có thể xảy ra với các đối tượng được tuần tự hóa. Để biết thêm thông tin, hãy xem Phiên nên được phép lưu trữ đối tượng (dotnet/aspnetcore #18159).

TempData

ASP.NET Core hiển thị Razor Pages TempData hoặc Controller TempData. Property này lưu trữ dữ liệu cho đến khi nó được đọc trong một yêu cầu khác. Các  phương thức Keep(String) và Peek(string) có thể được sử dụng để kiểm tra dữ liệu mà không cần xóa ở cuối yêu cầu. Giữ đánh dấu tất cả các mục trong từ điển để lưu giữ. TempData là:

  • Hữu ích cho việc chuyển hướng khi dữ liệu được yêu cầu cho nhiều hơn một yêu cầu.
  • TempData được các nhà cung cấp triển khai bằng cách sử dụng cookie hoặc trạng thái phiên.

Mẫu TempData

Hãy xem xét trang sau tạo ra một khách hàng:

public class CreateModel : PageModel
{
    private readonly RazorPagesContactsContext _context;

    public CreateModel(RazorPagesContactsContext context)
    {
        _context = context;
    }

    public IActionResult OnGet()
    {
        return Page();
    }

    [TempData]
    public string Message { get; set; }

    [BindProperty]
    public Customer Customer { get; set; }

    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        _context.Customer.Add(Customer);
        await _context.SaveChangesAsync();
        Message = $"Customer {Customer.Name} added";

        return RedirectToPage("./IndexPeek");
    }
}

Trang sau hiển thị TempData["Message"]:

@page
@model IndexModel

<h1>Peek Contacts</h1>

@{
    if (TempData.Peek("Message") != null)
    {
        <h3>Message: @TempData.Peek("Message")</h3>
    }
}

@*Content removed for brevity.*@

Trong đánh dấu trên, ở cuối yêu cầu, TempData["Message"] không bị xóa vì Peek được sử dụng. Nếu ta làm mới trang sẽ hiển thị nội dung của TempData["Message"].

Đánh dấu sau tương tự như code ở trên, nhưng sử dụng Keep để bảo toàn dữ liệu ở cuối yêu cầu:

@page
@model IndexModel

<h1>Contacts Keep</h1>

@{
    if (TempData["Message"] != null)
    {
        <h3>Message: @TempData["Message"]</h3>
    }
    TempData.Keep("Message");
}

@*Content removed for brevity.*@

Điều hướng giữa các trang IndexPeek và IndexKeep sẽ không xóa TempData["Message"].

Đoạn mã sau hiển thị TempData["Message"], nhưng ở cuối yêu cầu thì TempData["Message"] sẽ bị xóa:

@page
@model IndexModel

<h1>Index no Keep or Peek</h1>

@{
    if (TempData["Message"] != null)
    {
        <h3>Message: @TempData["Message"]</h3>
    }
}

@*Content removed for brevity.*@

Nhà cung cấp TempData

Nhà cung cấp TempData dựa trên cookie được sử dụng theo mặc định để lưu trữ TempData trong cookie.

Dữ liệu cookie được mã hóa bằng IDataProtector, được mã hóa bằng Base64UrlTextEncoder, sau đó được phân đoạn. Kích thước cookie tối đa nhỏ hơn 4096 byte do mã hóa và phân đoạn. Dữ liệu cookie không được nén vì việc nén dữ liệu được mã hóa có thể dẫn đến các sự cố bảo mật như các cuộc tấn công CRIME và BREACH. Để biết thêm thông tin về nhà cung cấp TempData dựa trên cookie, hãy xem  CookieTempDataProvider.

Chọn nhà cung cấp TempData

Việc chọn nhà cung cấp TempData liên quan đến một số cân nhắc, chẳng hạn như:

  • Ứng dụng đã sử dụng trạng thái phiên chưa? Nếu vậy, việc sử dụng nhà cung cấp TempData ở trạng thái phiên sẽ không tính thêm chi phí cho ứng dụng ngoài kích thước của dữ liệu.
  • Ứng dụng có sử dụng TempData ít cho lượng dữ liệu tương đối nhỏ, tối đa 500 byte không? Nếu vậy, nhà cung cấp cookie TempData sẽ thêm một khoản chi phí nhỏ cho mỗi yêu cầu mang TempData. Nếu không, nhà cung cấp TempData trạng thái phiên có thể hữu ích để tránh lặp lại một lượng lớn dữ liệu trong mỗi yêu cầu cho đến khi TempData được sử dụng.
  • Ứng dụng có chạy trong cụm máy chủ trên nhiều máy chủ không? Nếu vậy, không cần cấu hình bổ sung để sử dụng nhà cung cấp TempData cookie bên ngoài Bảo vệ dữ liệu. Để biết thêm thông tin, hãy xem Tổng quan về bảo vệ dữ liệu ASP.NET Core và Nhà cung cấp lưu trữ khóa.

Hầu hết các ứng dụng khách web chẳng hạn như trình duyệt web đều thực thi các giới hạn về kích thước tối đa của mỗi cookie và tổng số cookie. Khi sử dụng nhà cung cấp cookie TempData, hãy xác minh rằng ứng dụng sẽ không vượt quá các giới hạn này. Xem xét tổng kích thước của dữ liệu. Tài khoản để tăng kích thước cookie do mã hóa và chunking.

Định cấu hình nhà cung cấp TempData

Nhà cung cấp TempData dựa trên cookie được bật theo mặc định.

Để kích hoạt nhà cung cấp TempData dựa trên phiên, hãy sử dụng phương thức mở rộng AddSessionStateTempDataProvider. Chỉ cần một lời gọi AddSessionStateTempDataProvider được thực hiện:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages()
                    .AddSessionStateTempDataProvider();
builder.Services.AddControllersWithViews()
                    .AddSessionStateTempDataProvider();

builder.Services.AddSession();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.UseSession();

app.MapRazorPages();
app.MapDefaultControllerRoute();

app.Run();

Chuỗi truy vấn

Một lượng dữ liệu hạn chế có thể được chuyển từ yêu cầu này sang yêu cầu khác bằng cách thêm dữ liệu đó vào chuỗi truy vấn của yêu cầu mới. Điều này hữu ích để nắm bắt trạng thái một cách liên tục cho phép chia sẻ các liên kết có trạng thái nhúng được chia sẻ qua email hoặc mạng xã hội. Vì chuỗi truy vấn URL là công khai nên không bao giờ sử dụng chuỗi truy vấn cho dữ liệu nhạy cảm.

Ngoài việc chia sẻ ngoài ý muốn, việc bao gồm dữ liệu trong chuỗi truy vấn có thể khiến ứng dụng bị tấn công Giả mạo yêu cầu trên nhiều trang web (CSRF). Mọi trạng thái phiên được bảo toàn phải bảo vệ chống lại các cuộc tấn công CSRF. Để biết thêm thông tin, hãy xem Ngăn chặn các cuộc tấn công giả mạo yêu cầu chéo trang (XSRF/CSRF) trong ASP.NET Core.

Trường ẩn

Dữ liệu có thể được lưu trong các trường ẩn và đăng lại vào yêu cầu tiếp theo. Điều này là phổ biến trong các form nhiều trang. Vì ứng dụng khách có khả năng giả mạo dữ liệu nên ứng dụng phải luôn xác thực lại dữ liệu được lưu trữ trong các trường ẩn.

HttpContext.Items

Collection HttpContext.Items được sử dụng để lưu trữ dữ liệu trong khi xử lý một yêu cầu. Nội dung của bộ sưu tập bị loại bỏ sau khi yêu cầu được xử lý. Collection Items thường được sử dụng để cho phép các component hoặc middleware giao tiếp khi chúng hoạt động tại các thời điểm khác nhau trong một yêu cầu và không có cách nào trực tiếp để truyền tham số.

Trong ví dụ sau, middleware sẽ thêm isVerified vào collection Items:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

ILogger logger = app.Logger;

app.Use(async (context, next) =>
{
    // context.Items["isVerified"] is null
    logger.LogInformation($"Before setting: Verified: {context.Items["isVerified"]}");
    context.Items["isVerified"] = true;
    await next.Invoke();
});

app.Use(async (context, next) =>
{
    // context.Items["isVerified"] is true
    logger.LogInformation($"Next: Verified: {context.Items["isVerified"]}");
    await next.Invoke();
});

app.MapGet("/", async context =>
{
    await context.Response.WriteAsync($"Verified: {context.Items["isVerified"]}");
});

app.Run();

Đối với middleware chỉ được sử dụng trong một ứng dụng, việc sử dụng khóa string cố định sẽ không gây ra xung đột khóa. Tuy nhiên, để tránh khả năng xảy ra xung đột khóa hoàn toàn, một object có thể sử dụng một khóa làm khóa item. Cách tiếp cận này đặc biệt hữu ích cho middleware được chia sẻ giữa các ứng dụng và cũng có ưu điểm là loại bỏ việc sử dụng các chuỗi khóa trong mã. Ví dụ sau đây cho thấy cách sử dụng khóa object được xác định trong lớp middleware:

public class HttpContextItemsMiddleware
{
    private readonly RequestDelegate _next;
    public static readonly object HttpContextItemsMiddlewareKey = new();

    public HttpContextItemsMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext httpContext)
    {
        httpContext.Items[HttpContextItemsMiddlewareKey] = "K-9";

        await _next(httpContext);
    }
}

public static class HttpContextItemsMiddlewareExtensions
{
    public static IApplicationBuilder 
        UseHttpContextItemsMiddleware(this IApplicationBuilder app)
    {
        return app.UseMiddleware<HttpContextItemsMiddleware>();
    }
}

Đoạn code sau đây có thể truy cập giá trị được lưu trữ vào HttpContext.Items sử dụng khóa được hiển thị bởi lớp middleware:

public class Index2Model : PageModel
{
    private readonly ILogger<Index2Model> _logger;

    public Index2Model(ILogger<Index2Model> logger)
    {
        _logger = logger;
    }

    public void OnGet()
    {
        HttpContext.Items
            .TryGetValue(HttpContextItemsMiddleware.HttpContextItemsMiddlewareKey,
                out var middlewareSetValue);

        _logger.LogInformation("Middleware value {MV}",
            middlewareSetValue?.ToString() ?? "Middleware value not set!");
    }
}

Cache

Cache (Bộ nhớ đệm) là một cách hiệu quả để lưu trữ và truy xuất dữ liệu. Ứng dụng có thể kiểm soát thời gian tồn tại của các mục được lưu trong bộ nhớ cache. Để biết thêm thông tin, hãy xem Bộ nhớ đệm phản hồi trong ASP.NET Core.

Dữ liệu được lưu trong bộ nhớ cache không được liên kết với một yêu cầu, người dùng hoặc phiên cụ thể. Không lưu trữ dữ liệu cụ thể của người dùng có thể được truy xuất bởi các yêu cầu của người dùng khác.

Để lưu dữ liệu trên toàn bộ ứng dụng vào bộ nhớ cache, hãy xem Bộ nhớ cache trong bộ nhớ trong ASP.NET Core.

Kiểm tra trạng thái phiên

ISession.IsAvailable được dùng để kiểm tra các lỗi tạm thời. Gọi IsAvailable trước khi middleware phiên chạy sẽ ném file InvalidOperationException.

Các thư viện cần kiểm tra tính khả dụng của phiên có thể sử dụng HttpContext.Features.Get<ISessionFeature>()?.Session != null.

Lỗi thông thường

  • "Unable to resolve service for type 'Microsoft.Extensions.Caching.Distributed.IDistributedCache' while attempting to activate 'Microsoft.AspNetCore.Session.DistributedSessionStore'."

Điều này thường xảy ra do không thể định cấu hình ít nhất một triển khai IDistributedCache. Để biết thêm thông tin, hãy xem Bộ nhớ đệm được phân phối trong ASP.NET Core và Bộ nhớ đệm trong bộ nhớ đệm trong ASP.NET Core.

Nếu middleware phiên không duy trì phiên:

  • Middleware ghi nhật ký ngoại lệ và yêu cầu tiếp tục bình thường.
  • Điều này dẫn đến hành vi không thể đoán trước.

Middleware phiên không thể duy trì phiên nếu không có store sao lưu. Ví dụ: người dùng lưu trữ giỏ hàng trong phiên. Người dùng thêm một mặt hàng vào giỏ hàng nhưng commit không thành công. Ứng dụng không biết về lỗi nên ứng dụng báo cáo cho người dùng rằng mặt hàng đã được thêm vào thùng hàng của họ, điều này là không đúng.

Phương pháp được đặt ra để kiểm tra lỗi là gọi await feature.Session.CommitAsync khi ứng dụng ghi xong vào phiên. Commit Async đưa ra một ngoại lệ nếu store sao lưu không khả dụng. Nếu  CommitAsync không thành công, thì ứng dụng có thể xử lý ngoại lệ. LoadAsync sẽ được ném trong các điều kiện tương tự khi store lưu trữ dữ liệu không khả dụng.

Thêm tài nguyên

Xem hoặc tải xuống code mẫu (cách tải xuống)

Lưu trữ ASP.NET Core trong trang web

Nguồn: learn.microsoft.com
» Tiếp: Triển khai ứng dụng web ASP.NET
Khóa học qua video:
Lập trình Python All C# Lập trình C Java SQL Server PHP HTML5-CSS3-JavaScript
Đăng ký Hội viên
Tất cả các video dành cho hội viên
Copied !!!