۲۹ شهریور ۱۴۰۳

Techboy

اخبار و اطلاعات روز تکنولوژی

یک کنترل کننده احراز هویت برای حداقل API در ASP.NET Core بسازید

نحوه پیاده سازی احراز هویت اولیه رمز عبور برای یک API حداقل در ASP.NET Core با استفاده از یک کنترل کننده احراز هویت سفارشی که اعتبار کاربر را در برابر پایگاه داده تأیید می کند.

نحوه پیاده سازی احراز هویت اولیه رمز عبور برای یک API حداقل در ASP.NET Core با استفاده از یک کنترل کننده احراز هویت سفارشی که اعتبار کاربر را در برابر پایگاه داده تأیید می کند.

ASP.NET Core یک مدل میزبانی ساده به نام حداقل API ارائه می دهد که به ما امکان می دهد API های سبک وزن با حداقل وابستگی بسازیم. با این حال، “حداقل” به معنای حداقل امنیت نیست. حداقل APIها نیز نیاز به احراز هویت دارند.

ما احراز هویت JWT را در پست قبلی اینجا بررسی کرده‌ایم. در این مقاله بررسی خواهیم کرد که چگونه می توانیم یک کنترل کننده احراز هویت اولیه برای حداقل API ها در ASP.NET Core بسازیم. در زیر یک کنترل کننده اصلی احراز هویت را پیاده سازی می کنیم که کاربر را شناسایی و احراز هویت می کند. از آنجا که ما هویت کاربر را با استفاده از اعتبارنامه‌های ذخیره شده در پایگاه داده تأیید می‌کنیم، از Entity Framework Core استفاده خواهیم کرد.

برای استفاده از نمونه کدهای ارائه شده در این مقاله، باید Visual Studio 2022 را در سیستم خود نصب کنید. اگر قبلاً نسخه‌ای ندارید، می‌توانید Visual Studio 2022 را از اینجا دانلود کنید.

یک پروژه ASP.NET Core Web API در Visual Studio 2022 ایجاد کنید

برای ایجاد یک پروژه ASP.NET Core Web API در Visual Studio 2022، مراحل ذکر شده در زیر را دنبال کنید.

  1. Visual Studio 2022 IDE را راه اندازی کنید.
  2. روی “ایجاد پروژه جدید” کلیک کنید.
  3. در پنجره “ایجاد پروژه جدید”، “ASP.NET Core Web API” را از لیست الگوهای نمایش داده شده انتخاب کنید.
  4. بعدی را کلیک کنید.
  5. در پنجره “پیکربندی پروژه جدید خود”، نام و مکان پروژه جدید را مشخص کنید. به صورت اختیاری، بسته به تنظیمات برگزیده خود، کادر انتخاب «قرار دادن راه حل و پروژه در یک فهرست» را علامت بزنید.
  6. بعدی را کلیک کنید.
  7. در پنجره «اطلاعات اضافی» که در ادامه نشان داده شده است، «.NET 8.0 (Long Term Support)» را به عنوان نسخه فریمورک انتخاب کنید و تیک کادری که می گوید «استفاده از کنترلرها» را بردارید، زیرا ما در این مورد از حداقل API استفاده خواهیم کرد. پروژه.
  8. در جای دیگری از پنجره «اطلاعات اضافی»، «نوع احراز هویت» را روی «هیچ‌کدام» (پیش‌فرض) بگذارید و مطمئن شوید که کادرهای «فعال کردن پشتیبانی باز API»، «پیکربندی برای HTTPS» و «فعال کردن داکر» را انتخاب کنید. ” کنترل نشده باقی بماند. ما در اینجا از هیچ یک از این ویژگی ها استفاده نخواهیم کرد.
  9. روی ایجاد کلیک کنید.

ما از این پروژه ASP.NET Core Web API برای کار با نمونه کدهای ارائه شده در بخش های زیر استفاده خواهیم کرد.

یک API حداقل در ASP.NET Core ایجاد کنید

می توانید کد تولید شده را با قطعه کد زیر جایگزین کنید تا یک API حداقلی اولیه ایجاد کنید.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello, World!");
app.Run();

هنگامی که برنامه را اجرا می کنید، متن “Hello World!” در مرورگر وب شما نمایش داده می شود.

احراز هویت را در یک API حداقل فعال کنید

احراز هویت فرآیندی است برای تعیین هویت کاربر و تأیید هویت کاربر. (زمانی که کاربر احراز هویت شد، می‌توانیم نقش‌هایی را که کاربر باید در برنامه به آنها دسترسی داشته باشد، تعیین کنیم. این فرآیند به عنوان مجوز شناخته می‌شود.)

تولید کاملاً محلی با بازیابی، گام به گام

می‌توانید با استفاده از روش AddAuthentication() همانطور که در قطعه کد زیر نشان داده شده است، احراز هویت را در یک API حداقل در ASP.NET Core فعال کنید.

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication();
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();

بسته EF Core NuGet را نصب کنید

ما از قابلیت‌های موجود در حافظه Entity Framework Core برای ذخیره اعتبار کاربری خود برای احراز هویت استفاده خواهیم کرد. برای افزودن بسته Microsoft.EntityFrameworkCore.InMemory به پروژه خود، پروژه را در پنجره Solution Explorer انتخاب کنید، سپس کلیک راست کرده و “Manage NuGet Packages” را انتخاب کنید. در پنجره NuGet Package Manager، بسته Microsoft.EntityFrameworkCore.InMemory را جستجو کرده و آن را نصب کنید.

از طرف دیگر، می‌توانید بسته را از طریق کنسول NuGet Package Manager با وارد کردن دستور زیر نصب کنید.

PM> Install-Package Microsoft.EntityFrameworkCore.InMemory

یک DbContext جدید در EF Core ایجاد کنید

DbContext یک جزء جدایی ناپذیر از Entity Framework Core است که یک جلسه اتصال با پایگاه داده را نشان می دهد. یک کلاس جدید به نام CustomDbContext با گسترش کلاس DbContext EF Core ایجاد کنید و کد زیر را در آنجا وارد کنید.

public class CustomDbContext : DbContext
{
    protected override void OnConfiguring
   (DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseInMemoryDatabase(databaseName: "IDGSampleDb");
    }
    public DbSet<User> Users { get; set; }
}

یک کلاس کاربری در ASP.NET Core ایجاد کنید

یک کلاس جدید به نام User در فایلی به نام User.cs ایجاد کنید و کد زیر را در آن بنویسید. ما از این کلاس برای ذخیره کاربران و گذرواژه‌هایشان برای احراز هویت استفاده می‌کنیم.

public class User
{
    public string Username { get; set; }
    public string Password { get; set; }
}

یک نمونه از کلاس User ما در اینجا اعتبار یک کاربر را در حافظه ذخیره می کند. به طور معمول، مطمئناً اعتبار یک کاربر به طور دائم در پایگاه داده باقی می ماند.

یک کلاس UserService برای تأیید اعتبار کاربری ایجاد کنید

بعد اجازه دهید کلاسی به نام UserService ایجاد کنیم که منطق مورد نیاز برای اعتبارسنجی اعتبار کاربر را کپسوله می کند. متد Authenticate یک نمونه از کلاس User را در صورتی برمی‌گرداند که اعتبار کاربری که به عنوان پارامتر به آن ارسال شده است معتبر باشد.

قطعه کد زیر کلاس UserService را نشان می دهد.

public class UserService : IUserService
{
    private readonly CustomDbContext _dbContext;
    public UserService(CustomDbContext customDbContext)
    {
        this._dbContext = customDbContext;
    }
    public async Task<User> Authenticate(string username, string password)
    {
        var user = await Task.Run(() =>
        _dbContext.Users.SingleOrDefault
        (x => x.Username == username && x.Password == password));
        return user;
    }
}

واسط IUserService در زیر برای مرجع شما آورده شده است.

public interface IUserService
{
    Task<User> Authenticate(string username, string password);
}

طرح‌های احراز هویت و کنترل‌کننده‌های احراز هویت

در ASP.NET Core، یک طرح احراز هویت برای تعیین نحوه احراز هویت برای یک درخواست استفاده می شود. یک طرح احراز هویت شامل مجموعه‌ای از گزینه‌ها و رفتار نام‌گذاری شده است که توسط یک کنترل‌کننده احراز هویت محصور شده‌اند.

یک کنترل کننده احراز هویت در ASP.NET Core نوعی است که رفتار یک طرح احراز هویت را پیاده سازی می کند. یک کنترل کننده احراز هویت رابط IAuthenticationHandler یا نوع AuthenticationHandler را گسترش می دهد. یک کنترل کننده احراز هویت بسته به موفقیت یا عدم موفقیت فرآیند احراز هویت باید موفقیت یا شکست را برگرداند.

وقتی کم کد و بدون کد می تواند به نوسازی اپلیکیشن سرعت ببخشد

یک طرح احراز هویت برای حداقل API ایجاد کنید

قبل از ایجاد یک کنترل کننده احراز هویت سفارشی، ابتدا باید یک نوع AuthenticationSchemeOptions سفارشی مانند شکل زیر ایجاد کنید.

public class CustomAuthenticationSchemeOptions : AuthenticationSchemeOptions
{
    public const string DefaultScheme = "BasicAuthentication";
    public const string AuthorizationHeaderName = "Authorization";
}

بعد یک کلاس جدید به نام User در فایلی به نام User.cs ایجاد کنید و کد زیر را وارد کنید.

public class User
{
    public string Username { get; set; }
    public string Password { get; set; }
}

در قطعه کد بالا، توجه داشته باشید که چگونه طرح احراز هویت را مشخص کرده‌ایم. طرح‌های احراز هویت برای جلوگیری از هرگونه دسترسی غیرمجاز به اطلاعات حساس با تأیید هویت کاربر، دستگاه یا موجودیت قبل از اعطای دسترسی به یک منبع استفاده می‌شود. در این مثال، طرح احراز هویت پیش‌فرض به‌عنوان BasicAuthentication مشخص شده است.

در احراز هویت اولیه، یک کلاینت در حین ارسال درخواست HTTP به سرور، اعتبارنامه ها را به صورت متن ساده ارسال می کند. اگر درخواست قانونی نباشد، سرور یک کد وضعیت غیرمجاز HTTP 401 را برمی‌گرداند که نشان می‌دهد احراز هویت ناموفق بوده است. AuthorizationHeaderName نام هدر HTTP را نشان می دهد که برای انتقال اعتبارنامه ها به عنوان بخشی از درخواست HTTP استفاده می شود.

یک کنترل کننده احراز هویت برای حداقل API ایجاد کنید

در هسته ASP.NET، روش HandleAuthenticateAsync در یک کنترل کننده احراز هویت برای کپسوله کردن کد برای احراز هویت یک درخواست استفاده می شود. این روش بخشی از کلاس AuthenticationHandler است.

شما باید روش HandleAuthenticateAsync را در کنترل کننده احراز هویت سفارشی خود از جمله کد سفارشی خود برای احراز هویت یک درخواست پیاده سازی کنید. فهرست کد زیر اجرای روش لغو شده HandleAuthenticateAsync را نشان می دهد.

protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
    if (!Request.Headers.ContainsKey(CustomAuthenticationOptions.AuthorizationHeaderName))
    {
        return AuthenticateResult.Fail("Unauthorized");
    }
    var authenticationHeaderValue = Request.Headers[CustomAuthenticationOptions.AuthorizationHeaderName];
    if (string.IsNullOrEmpty(authenticationHeaderValue))
    {
        return AuthenticateResult.NoResult();
    }
    User user;
    try
    {
        var authenticationHeader = AuthenticationHeaderValue.Parse(authenticationHeaderValue);
        var credentialBytes = Convert.FromBase64String(authenticationHeader.Parameter);
        var credentials = Encoding.UTF8.GetString(credentialBytes).Split(new[] { ':' }, 2);
        var username = credentials[0];
        var password = credentials[1];
        user = new User()
        {
             Username = username,
             Password = password
        };

    user = await _userService.Authenticate(username, password);

        if (user == null)
            return AuthenticateResult.Fail("Invalid Username or Password");
    }
    catch
    {
        return AuthenticateResult.Fail("Invalid Authorization Header");
    }
    var claims = new List<Claim>()
    {
        new Claim("Username", user.Username)
    };
    var claimsIdentity = new ClaimsIdentity(claims, Scheme.Name);
    var claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
    return AuthenticateResult.Success
        (new AuthenticationTicket(claimsPrincipal,
        this.Scheme.Name));
}

روش HandleAuthenticateAsync وجود هدر مجوز را تأیید می کند. اگر وجود نداشته باشد، کنترل کننده احراز هویت یک نمونه AuthenticateResult را نشان می دهد که یک شکست را نشان می دهد. اگر هدر مجوز وجود داشته باشد، کنترل کننده داده های موجود در هدر مجوز را بازیابی می کند. سپس این داده ها برای بازیابی نام کاربری و رمز عبور کاربر که در هدر مجوز درخواست HTTP ارسال شده است، تجزیه می شود.

سپس اعتبارنامه های بازیابی شده در مقابل پایگاه داده تایید می شوند. اگر اعتبارنامه ها معتبر نباشند، یک نمونه AuthorizationResult برگردانده می شود که نشان دهنده شکست است. اگر اعتبارنامه ها معتبر باشند، یک نمونه ادعا ایجاد می شود و سپس از طریق یک بلیط مجوز عبور می کند. سپس این بلیط با استفاده از یک نمونه از AuthenticateResult برگردانده می‌شود تا به ماژول‌های باقی‌مانده خط لوله اجازه دهد تا طبق معمول اجرا شوند.

C# 12 کامپایل AOT را تقویت می کند

کنترل کننده احراز هویت را در ASP.NET Core ثبت کنید

برای ثبت کنترل کننده احراز هویت سفارشی با خط لوله پردازش درخواست، باید کد زیر را در فایل Program.cs قرار دهید.

builder.Services.AddAuthentication
    (CustomAuthenticationOptions.DefaultScheme)
    .AddScheme<CustomAuthenticationOptions, CustomAuthenticationHandler>
    (CustomAuthenticationOptions.DefaultScheme,
        options => { });

در نهایت، باید کد زیر را در فایل Program.cs قرار دهید تا از احراز هویت و مجوز استفاده کنید.

app.UseAuthentication();
app.UseAuthorization();

مثال کنترل کننده احراز هویت کامل در ASP.NET Core

کد منبع کامل کنترل کننده احراز هویت سفارشی برای مرجع شما در زیر آورده شده است.

public class CustomAuthenticationHandler :
    AuthenticationHandler<CustomAuthenticationOptions>
{
    public CustomAuthenticationHandler
        (IOptionsMonitor<CustomAuthenticationOptions> options,
        ILoggerFactory logger, UrlEncoder encoder,
        ISystemClock clock)
        : base(options, logger, encoder, clock)
    { }
    protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        if (!Request.Headers.ContainsKey(CustomAuthenticationOptions.AuthorizationHeaderName))
        {
            return AuthenticateResult.Fail("Unauthorized");
        }
        var authenticationHeaderValue = Request.Headers[CustomAuthenticationOptions.AuthorizationHeaderName];
       if (string.IsNullOrEmpty(authenticationHeaderValue))
        {
            return AuthenticateResult.NoResult();
        }
        User user = null;
        try
        {
            var authenticationHeader = AuthenticationHeaderValue.Parse(authenticationHeaderValue);
            var credentialBytes = Convert.FromBase64String(authenticationHeader.Parameter);
            var credentials = Encoding.UTF8.GetString(credentialBytes).Split(new[] { ':' }, 2);
            var username = credentials[0];
            var password = credentials[1];
            user = new User()
            {
                 Username = username,
                 Password = password
            };
            if (user == null)
                return AuthenticateResult.Fail("Invalid credentials");
        }
        catch
        {
            return AuthenticateResult.Fail("Authorization Header is invalid");
        }
        var claims = new List<Claim>()
        {
            new Claim("Username", user.Username)
        };
        var claimsIdentity = new ClaimsIdentity(claims, Scheme.Name);
        var claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
        return AuthenticateResult.Success
            (new AuthenticationTicket(claimsPrincipal,
            this.Scheme.Name));
    }
}

یک نقطه پایانی HTTP برای آزمایش کنترل کننده احراز هویت ایجاد کنید

قطعه کد زیر را در نظر بگیرید که نشان می دهد چگونه می توانید یک نقطه پایانی HttpGet ایجاد کنید که نیاز به مجوز دارد. این نقطه پایانی تنها در صورتی فراخوانی می‌شود که اعتبارنامه صحیح را ارائه کنید.

app.MapGet("/test", [Authorize] async ([FromBody] User user) =>
{
    var userName = user.Username;
    var password = user.Password;
    return Results.Ok();
});

در نهایت، هم برنامه و هم ابزار Postman را برای فراخوانی نقطه پایانی اجرا کنید. شکل ۱ نشان می دهد که چگونه می توانید نام کاربری و رمز عبور درخواست را در Postman مشخص کنید.

Auth handler minimal api 01

شکل ۱: پیکربندی احراز هویت اولیه در Postman.

اکنون می توانید نقطه پایانی /test را از Postman فراخوانی کنید. شکل ۲ نقطه پایانی /test را نشان می دهد که از Postman فراخوانی شده است.

auth handler minimal api 02

شکل ۲: فراخوانی نقطه پایانی با استفاده از Postman.

اگر احراز هویت موفقیت آمیز باشد، نقطه پایانی API کد وضعیت HTTP 200 OK را برمی گرداند. اگر احراز هویت ناموفق باشد، نقطه پایانی API کد وضعیت غیرمجاز HTTP 401 را برمی‌گرداند.

اجرای حداقلی

توجه داشته باشید که پیاده سازی حداقلی ما در اینجا شامل هیچ کدی برای ذخیره اعتبار کاربر در پایگاه داده نمی شود. شما باید پیاده سازی خود را بنویسید تا اعتبارنامه ها را از کاربر بپذیرید و سپس آنها را در پایگاه داده زیرین ذخیره کنید. همچنین، برای سادگی، از یک پایگاه داده در حافظه در اینجا استفاده کرده ایم. البته باید از یک فروشگاه دائمی برای اعتبار کاربری در یک برنامه واقعی استفاده کنید.