Làm cách nào để sử dụng xác thực cookie trong .NET Core?

Cookie là một phần dữ liệu nhỏ được đặt trên trình duyệt của khách hàng, mà các ứng dụng có thể sử dụng để lưu trữ dữ liệu tồn tại trong thời gian ngắn. Xác thực dựa trên cookie là một khái niệm trong đó máy chủ lưu trữ một số bối cảnh được xác thực trong trình duyệt máy khách và sử dụng nó để quản lý các phiên của người dùng trong ứng dụng

Trong bài viết này, hãy xem cách chúng ta có thể thiết lập xác thực dựa trên cookie trong ASP. NET Core MVC không sử dụng thiết lập AspNetIdentity cho cửa hàng người dùng của nó

Thiết lập các thành phần dự án

Để bắt đầu, hãy tạo một ứng dụng web MVC đơn giản có tên là CookieReader có một trang Đăng nhập, Đăng ký và Hồ sơ cùng với trang Chỉ mục mặc định

> dotnet new mvc --name CookieReader

Chúng tôi sẽ sử dụng cơ sở dữ liệu SQLite để lưu trữ thông tin người dùng, được xử lý bởi Entity Framework Core để truy cập. Cơ sở dữ liệu được duy trì trong một tệp cục bộ có tên là ứng dụng. db. Đối với Entity Framework Core, hãy cài đặt các gói cần thiết

> dotnet add package Microsoft.EntityFrameworkCore.Design
> dotnet add package Microsoft.EntityFrameworkCore.Sqlite

Khi chúng tôi đã thêm các gói này, giờ đây chúng tôi sẽ có thể tạo và làm việc với các thực thể và bối cảnh cơ sở dữ liệu cho mục đích của chúng tôi. Người dùng được duy trì trong một bảng có tên là Người dùng và họ được truy cập trong ứng dụng bằng loại có tên là CookieUser. Để đơn giản hóa mọi thứ, tôi đã đánh dấu tất cả các chú thích dữ liệu cần thiết trong loại, một số có thể muốn nó được tách ra. Loại trông như dưới đây

namespace CookieReaders.Models.Entities
{
    public class CookieUser
    {
        [Key]
        public Guid Id { get; set; }
        public string EmailAddress { get; set; }
        public string PasswordHash { get; set; }
        public string Salt { get; set; }
        public string Name { get; set; }
        public DateTime CreatedUtc { get; set; } = DateTime.UtcNow;
    }
}

CookieUser lưu trữ kết hợp PasswordHash và Salt của nó thay vì lưu trữ mật khẩu trực tiếp, đây là cách thực hành tốt nhất về bảo mật và tính toàn vẹn. Vì chúng tôi không sử dụng AspNetIdentity, chúng tôi phải tạo kho lưu trữ người dùng và xác thực cho chính mình. Vì vậy, chúng tôi sẽ thiết lập một cửa hàng người dùng đơn giản với các thuộc tính tối thiểu và cơ chế mật khẩu

Bối cảnh cơ sở dữ liệu để lưu trữ người dùng

Bối cảnh cơ sở dữ liệu ánh xạ lớp này tới cơ sở dữ liệu là CookieReadersContext và như bên dưới

namespace CookieReaders.Models.Entities
{
    public class CookieReadersContext : DbContext
    {
        public CookieReadersContext[DbContextOptions options] : base[options]
        {
        }

        public DbSet Users { get; set; }
    }
}

Để hoàn thành ánh xạ cơ sở dữ liệu, hãy đăng ký CookieReadersContext này trong ConfigureServices và chạy di chuyển để tạo lược đồ bảng

services.AddDbContext[options =>
{
    options.UseSqlite["Data Source=app.db"];
}];
> dotnet ef migrations add InitialCreate
> dotnet ef database update

Khi các bước này hoàn tất, chúng tôi sẽ thiết lập cơ sở dữ liệu sẵn sàng để lưu trữ và truy xuất Người dùng từ cửa hàng. Bây giờ chúng tôi sẽ kết nối bối cảnh này trong các trang Đăng nhập, Đăng ký của chúng tôi

Các kho lưu giữ Logic nghiệp vụ

Chúng tôi thực hiện điều đó thông qua loại Kho lưu trữ người dùng gói gọn logic xác thực. Loại này cũng chịu trách nhiệm tạo và xác thực mật khẩu phù hợp

Loại triển khai giao diện IUserRepository và như bên dưới

namespace CookieReaders.Providers.Repositories
{
    public interface IUserRepository
    {
        CookieUserItem Register[RegisterVm model];
        CookieUserItem Validate[LoginVm model];
    }

    public class UserRepository : IUserRepository
    {
        private CookieReadersContext _db;

        public UserRepository[CookieReadersContext db]
        {
            _db = db;
        }

        public CookieUserItem Validate[LoginVm model]
        {
            var emailRecords = _db.Users.Where[x => x.EmailAddress == model.EmailAddress];

            var results = emailRecords.AsEnumerable[]
            .Where[m => m.PasswordHash == Hasher.GenerateHash[model.Password, m.Salt]]
            .Select[m => new CookieUserItem
            {
                UserId = m.Id,
                EmailAddress = m.EmailAddress,
                Name = m.Name,
                CreatedUtc = m.CreatedUtc
            }];

            return results.FirstOrDefault[];
        }

        public CookieUserItem Register[RegisterVm model]
        {
            var salt = Hasher.GenerateSalt[];
            var hashedPassword = Hasher.GenerateHash[model.Password, salt];

            var user = new CookieUser
            {
                Id = Guid.NewGuid[],
                EmailAddress = model.EmailAddress,
                PasswordHash = hashedPassword,
                Salt = salt,
                Name = "Some User",
                CreatedUtc = DateTime.UtcNow
            };

            _db.Users.Add[user];
            _db.SaveChanges[];

            return new CookieUserItem
            {
                UserId = user.Id,
                EmailAddress = user.EmailAddress,
                Name = user.Name,
                CreatedUtc = user.CreatedUtc
            };
        }
    }
}

Nó đưa ra hai phương pháp; . Trong cả hai trường hợp, kho lưu trữ trả về đối tượng CookieUserItem kết quả là phép chiếu trên thực thể CookieUser trừ đi các trường mật khẩu

using System;

namespace CookieReaders.Models
{
    public class CookieUserItem
    {
        public Guid UserId { get; set; }
        public string EmailAddress { get; set; }
        public string Name { get; set; }
        public DateTime CreatedUtc { get; set; } = DateTime.UtcNow;
    }
}

Cho đến thời điểm này, chúng tôi đã hoàn thành việc kết nối lớp cơ sở dữ liệu của mình và xây dựng logic cần thiết để lưu trữ và xác thực dữ liệu người dùng cho các trường hợp đăng nhập người dùng hiện tại và đăng ký người dùng mới. Chúng tôi cũng đã xây dựng các giao diện được sử dụng bởi lớp giao diện người dùng dưới dạng kho lưu trữ, để tách giao diện người dùng khỏi miền

Bây giờ chúng ta chuyển sang phần cơ bản – thêm Xác thực cookie và sau đó đăng ký ngữ cảnh cookie trong trường hợp đăng nhập hoặc đăng ký thành công

Thiết lập xác thực – Thêm phần mềm trung gian cookie

Để bắt đầu, chúng tôi thêm phần mềm trung gian Xác thực cookie để đảm bảo sự tồn tại của cookie và xác thực chúng. Chúng tôi thêm nó dưới dạng một chuỗi vào dịch vụ AddAuthentication[], để chỉ định cho thời gian chạy AspNetCore dịch vụ xác thực nào sẽ được sử dụng. Điều này tương tự như việc thêm dịch vụ xác thực JwtBearer cho trường hợp Xác thực dựa trên mã thông báo

________số 8

Trong khối mã trên, chúng tôi chỉ định DefaultScheme sẽ được sử dụng làm CookieAuthenticationDefaults. AuthenticationScheme là hằng số có giá trị “Cookies”. Cũng trong cấu hình dịch vụ AddCookie[], chúng tôi cung cấp đường dẫn Đăng nhập và Đăng xuất. Ứng dụng chuyển hướng đến các đường dẫn tương ứng này trong trường hợp đăng nhập hoặc đăng xuất

Chúng tôi thêm phần mềm trung gian Xác thực trong phương thức Configure[] để phương thức Xác thực này được chọn và thực thi cho mọi yêu cầu truy cập vào máy chủ. Điều này QUAN TRỌNG, vì toàn bộ quy trình xác thực mà chúng ta đang thực hiện sẽ không hoạt động nếu một dòng này không được thêm vào trong phương thức Configure[]

public void Configure[
    IApplicationBuilder app, IWebHostEnvironment env]
{
    if [env.IsDevelopment[]]
    {
        app.UseDeveloperExceptionPage[];
    }
    else
    {
        app.UseExceptionHandler["/Home/Error"];
        app.UseHsts[];
    }

    app.UseHttpsRedirection[];
    app.UseStaticFiles[];
    
    // ::IMPORTANT::
    // add authentication middleware
    // cookie auth doesn't work
    // if this is not added
    app.UseAuthentication[];

    app.UseRouting[];
    
    app.UseAuthorization[];

    app.UseEndpoints[endpoints =>
    {
        endpoints.MapControllerRoute[
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}"];
    }];
}

Cấu hình bộ điều khiển để trình bày

Tiếp theo, chúng tôi xác định các đường dẫn Hành động, Đăng nhập và Đăng xuất này và kết nối chúng với các kho lưu trữ phía sau của chúng tôi. Ngoài ra, chúng tôi cũng thêm hai luồng nữa. một là quy trình Đăng ký để tạo người dùng mới trong cơ sở dữ liệu và cái còn lại là đường dẫn Hồ sơ nơi chúng ta chỉ thấy chi tiết người dùng đã đăng nhập. Chúng tôi cần thiết kế đường dẫn Hồ sơ này sao cho chỉ những người dùng đã đăng nhập mới có thể truy cập được

Lớp Trình điều khiển lưu trữ các đường dẫn này như bên dưới

> dotnet add package Microsoft.EntityFrameworkCore.Design
> dotnet add package Microsoft.EntityFrameworkCore.Sqlite
0

Trong lớp này, chúng tôi đã kết nối các mô hình xem Đăng nhập và Đăng ký sắp tới và chuyển những dữ liệu này vào các phương thức tương ứng để xác thực người dùng và tạo người dùng mới vào cơ sở dữ liệu. Bộ điều khiển [UI] được tách rời hoàn toàn khỏi triển khai phụ trợ [hạ tầng] và chỉ giao tiếp thông qua một bản tóm tắt [IUserRepository]

Quan sát rằng chúng tôi đã thêm thuộc tính Ủy quyền ở đầu hành động Hồ sơ. Tại sao?

Nhưng chúng ta đã xong việc ở đây chưa? . Chúng tôi vừa triển khai logic để xác thực yêu cầu đăng nhập/đăng ký đến và phản hồi lại. Trong bước tiếp theo, chúng tôi cần tạo AuthenticatedContext cho người dùng đã được xác thực thành công hoặc đăng ký thành công, sau đó thêm cookie vào trình duyệt để phiên đăng nhập được duy trì trong trình duyệt sau đó

Thiết lập bối cảnh xác thực với Trình quản lý người dùng

Chúng tôi duy trì chức năng này bên trong một lớp gọi là UserManager. Loại UserManager này triển khai IUserManager xác định hai phương thức; . Phương thức SignIn chứa logic để tạo LoginContext cho người dùng được xác thực và tạo cookie trong trình duyệt. Phương thức SignOut xóa cookie đã tạo này và đăng xuất người dùng

> dotnet add package Microsoft.EntityFrameworkCore.Design
> dotnet add package Microsoft.EntityFrameworkCore.Sqlite
1

Trước tiên hãy xem cách triển khai phương thức SignIn. Đây là một cách tiếp cận rất đơn giản mặc dù nghe có vẻ phức tạp. Chúng tôi làm theo các bước dưới đây

  1. Tạo Khiếu nại dựa trên thông tin Người dùng được xác thực
  2. Tạo một Xác nhận quyền sở hữu dựa trên các Xác nhận quyền sở hữu này
  3. Tạo một ClaimsPrincipal cho danh tính này
  4. chuyển ClaimsPrincipal này tới HttpContext. Phương thức SignIn, cùng với AuthenticationScheme; . Lược đồ xác thực

Đó là tất cả để nó

> dotnet add package Microsoft.EntityFrameworkCore.Design
> dotnet add package Microsoft.EntityFrameworkCore.Sqlite
2

Chúng tôi chuyển một số AuthenticationProperties cùng với ClaimsPrincipal khi đăng nhập. Các thuộc tính này định cấu hình một số thứ như thời gian tồn tại của cookie, url sẽ được chuyển hướng sau khi ngữ cảnh được xác thực, v.v. Hiện tại, chúng tôi không đặt bất kỳ giá trị nào trong số này để chúng ở cài đặt mặc định

Sau đó, chúng tôi gọi phương thức này bên trong các phương thức Đăng nhập và Đăng ký của bộ điều khiển

> dotnet add package Microsoft.EntityFrameworkCore.Design
> dotnet add package Microsoft.EntityFrameworkCore.Sqlite
3

Đối với Đăng xuất, chúng tôi chỉ cần vô hiệu hóa bối cảnh này để cookie bị xóa. Phương thức SignOut trong UserManager cũng làm như vậy. Chúng tôi sẽ chuyển AuthenticationScheme mà việc Đăng xuất này xảy ra

> dotnet add package Microsoft.EntityFrameworkCore.Design
> dotnet add package Microsoft.EntityFrameworkCore.Sqlite
4

Menu có điều kiện dựa trên bối cảnh Auth

Để xác minh rằng tất cả điều này đang hoạt động, chúng tôi sẽ có một hệ thống menu dựa trên điều kiện trong thanh điều hướng ứng dụng, hiển thị các bộ menu khác nhau cho người dùng được xác thực

> dotnet add package Microsoft.EntityFrameworkCore.Design
> dotnet add package Microsoft.EntityFrameworkCore.Sqlite
5

Trong menu này, chúng tôi đã thêm một điều kiện nếu-khác với dao cạo sao cho đối với những người dùng đã đăng nhập có Danh tính được đặt trong ngữ cảnh, chúng tôi sẽ có một liên kết để điều hướng đến “Hồ sơ” của họ được trang trí bằng thuộc tính Ủy quyền trong

Thuộc tính ủy quyền đảm bảo rằng chỉ cho phép truy cập được xác thực và khi người dùng chưa được xác thực cố gắng truy cập vào liên kết, anh ta sẽ được chuyển hướng đến Đường dẫn đăng nhập mặc định được định cấu hình trong phần mềm trung gian [“/Tài khoản/Đăng nhập”]

Chúng tôi cũng sẽ có một liên kết Đăng xuất chỉ dành cho những người dùng được xác thực. người dùng chưa được xác thực chỉ có thể thấy liên kết Đăng nhập trong menu

Xa hơn một chút – Thiết lập chính sách cookie

Với sự thay đổi gần đây trong quy tắc web toàn cầu, các ứng dụng hiện bắt buộc phải có sự đồng ý của người dùng để tạo cookie. Người dùng phải chấp nhận cookie mà ứng dụng tạo để tiếp tục sử dụng ứng dụng

Bây giờ chúng ta cần thêm một chút logic vào ứng dụng của mình để ứng dụng sẽ yêu cầu sự đồng ý từ người dùng để tạo cookie trong khi sử dụng ứng dụng. Đối với điều này, chúng tôi định cấu hình các tùy chọn CookiePolicy có sẵn trong lớp Khởi động như bên dưới

> dotnet add package Microsoft.EntityFrameworkCore.Design
> dotnet add package Microsoft.EntityFrameworkCore.Sqlite
6

Sau đó, chúng tôi thêm phần mềm trung gian tương ứng vào phương thức Configure[]

> dotnet add package Microsoft.EntityFrameworkCore.Design
> dotnet add package Microsoft.EntityFrameworkCore.Sqlite
7

Bây giờ chúng tôi tạo một cửa sổ bật lên cảnh báo đơn giản để người dùng được hiển thị khi họ mở ứng dụng. Cảnh báo này là một phần, kiểm tra xem người dùng đã chấp nhận chính sách cookie chưa. Nếu không, thông báo sẽ được hiển thị và khi người dùng nhấp vào Chấp nhận, chính sách sẽ thiết lập sự đồng ý trong trình duyệt. Điều này có sẵn cho đến khi trình duyệt bị xóa khỏi tất cả các cookie

> dotnet add package Microsoft.EntityFrameworkCore.Design
> dotnet add package Microsoft.EntityFrameworkCore.Sqlite
8

Làm thế nào thiết lập này hoạt động?

Để hiểu những gì xảy ra đằng sau hậu trường, hãy chạy ứng dụng của chúng tôi. Mã nguồn đầy đủ của ứng dụng chúng tôi đã tạo cho đến nay có sẵn trong kho lưu trữ để bạn có thể chỉ cần kéo mã đó

Khi chúng tôi chạy mã này, chúng tôi sẽ được đưa đến trang Chỉ mục hoặc Trang chủ. Và thanh điều hướng chứa liên kết Đăng nhập. Điều này là do chúng tôi hiện đang ở trạng thái chưa được xác thực. Nhấp vào liên kết và chúng tôi được đưa đến trang đăng nhập



Tìm thấy bài viết này hữu ích?

Nhấp vào liên kết để đăng ký và tạo người dùng mới. Ứng dụng lại chuyển hướng đến Trang chủ và bây giờ bạn có thể nhận thấy rằng thanh điều hướng hiện hiển thị các liên kết Hồ sơ và Đăng xuất thay vì Đăng nhập. Ngoài ra, Tên đã đăng nhập được hiển thị cho liên kết Hồ sơ, mang lại trải nghiệm người dùng tốt

Vậy chuyện gì đã xảy ra?

Khi chúng tôi đăng nhập/đăng ký và được chuyển hướng với ngữ cảnh được xác thực, chúng tôi thấy rằng phần Cookie hiện chứa khóa-giá trị cookie với một số giá trị được mã hóa

Và khi chúng tôi chấp nhận cảnh báo về sự đồng ý của cookie, trong nội bộ chúng tôi có một cookie khác được tạo với giá trị “có” nghĩa là chúng tôi đã chấp nhận sự đồng ý

Ví dụ đầy đủ có sẵn tại. https. //github. com/referbruv/cookie-authentication-example-aspnetcore

Xác thực cookie hoạt động như thế nào trong. NET lõi?

Xác thực cookie trong ASP như thế nào. NET Core có hoạt động không? .
Người dùng yêu cầu URL từ máy chủ
Dựa trên bộ truy cập, máy chủ sẽ trả lại trang nếu đó là trang công khai hoặc sẽ trả lại trang đăng nhập nếu đó là trang được bảo mật. e. yêu cầu người dùng đăng nhập để truy cập trang được bảo mật

Cách triển khai xác thực cookie trong ASP. NET lõi?

Hãy triển khai Xác thực cookie trong ASP. NET Core từng bước. Mở Visual Studio và nhấp vào Tạo dự án mới. Chọn ASP. NET Core Empty và nhấp vào tiếp theo. Đặt tên cho Dự án của bạn, chọn vị trí để tạo dự án và nhấp vào Tiếp theo.

Chủ Đề