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

Techboy

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

نحوه پیاده سازی احراز هویت JWT در ASP.NET Core

ایمن کردن حداقل نقاط پایانی API در ASP.NET Core با استفاده از JSON Web Tokens برای احراز هویت و مجوز آسان است. فقط این مراحل را دنبال کنید.

ایمن کردن حداقل نقاط پایانی API در ASP.NET Core با استفاده از JSON Web Tokens برای احراز هویت و مجوز آسان است. فقط این مراحل را دنبال کنید.

ASP.NET Core یک مدل میزبانی ساده به نام مینیال API، که به ما امکان می دهد API های سبک وزن با حداقل وابستگی بسازیم. API های حداقل برای ساخت میکروسرویس ها و API های سریع HTTP ایده آل هستند. به طور طبیعی، شما اغلب نیاز دارید که نقاط پایانی چنین API هایی را در برنامه های خود ایمن کنید. هدف این پست این است که شما را در انجام این کار شروع کنید.

ما درباره نحوه شروع با حداقل APIها، نحوه استفاده از ورود به سیستم و تزریق وابستگی در حداقل APIها و نحوه آزمایش حداقل API بحث کرده ایم. a> در مقالات قبلی این مقاله به این موضوع می‌پردازد که چگونه می‌توانیم حداقل نقاط پایانی API خود را با استفاده از احراز هویت JWT ایمن کنیم – به عنوان مثال، احراز هویت مبتنی بر توکن‌های وب JSON.

برای ایمن کردن حداقل API با استفاده از احراز هویت JWT، این مراحل را دنبال خواهیم کرد:

  1. یک پروژه حداقل API در Visual Studio 2022 ایجاد کنید.
  2. یک نقطه پایانی API در فایل Program.cs ایجاد کنید.
  3. بسته Microsoft.AspNetCore.Authentication.JwtBearer NuGet را به پروژه ما اضافه کنید.
  4. احراز هویت JWT را در فایل Program.cs پیاده سازی کنید.
  5. یک کلاس مدل کاربری با نام User ایجاد کنید تا اعتبار ورود به سیستم کاربر را ذخیره کنید.
  6. یک کلید مخفی را در فایل appsettings.json مشخص کنید.
  7. تنظیمات احراز هویت JWT را در فایل Program.cs مشخص کنید.
  8. در فایل Program.cs، میانافزار خدمات مجوز را به برنامه ما اضافه کنید.
  9. توکن وب JSON را در فایل Program.cs ایجاد و تأیید کنید.

توجه داشته باشید که همه نمونه‌های کد نشان داده شده در این پست، به جز کلاس User model، باید بخشی از Program.cs باشند. کلاس User model باید بخشی از فایل User.cs باشد.

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

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

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

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

ما از این پروژه ASP.NET Core Web API برای ایجاد یک نقطه پایانی API حداقل و اجرای احراز هویت JWT برای آن در بخش‌های بعدی این مقاله استفاده خواهیم کرد.

در ASP.NET Core یک HTTP Get ایجاد کنید

وقتی یک پروژه حداقل Web API در Visual Studio 2022 ایجاد می‌کنید، یک فایل Program.cs با چند خط کد پیش‌فرض ایجاد می‌شود. می‌توانید کد پیش‌فرض را با قطعه کد زیر جایگزین کنید تا همه چیز ساده باشد و همچنان راهی برای آزمایش API خود ارائه دهید.

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

به استفاده از روش افزونه RequireAuthorization در اینجا توجه کنید. این به شما کمک می کند با استفاده از خط مشی های مجوز از مسیرهای خود محافظت کنید و شما را مجبور می کند هنگام تماس با این نقطه پایانی اطلاعات احراز هویت را ارائه دهید. میان‌افزار مجوز از این اطلاعات برای تأیید درخواست برای زمینه اجرای فعلی استفاده می‌کند.

اگر این نقطه پایانی را بدون این اطلاعات اجرا کنید، همانطور که در شکل ۱ نشان داده شده است، با یک خطای غیرمجاز HTTP 401 مواجه خواهید شد.

secure minimal api 01

شکل ۱. یک خطای غیرمجاز HTTP 401 در صورت نیاز به مجوز و عدم ارائه اطلاعات مجوز ایجاد می‌شود.

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

اکنون بسته Microsoft.AspNetCore.Authentication.JwtBearer NuGet را به پروژه خود اضافه کنید. برای انجام این کار، پروژه را در پنجره Solution Explorer انتخاب کنید، سپس راست کلیک کرده و “Manage NuGet Packages” را انتخاب کنید. در پنجره NuGet Package Manager، بسته Microsoft.AspNetCore.Authentication.JwtBearer را جستجو کرده و آن را نصب کنید.

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

PM> Install-Package Microsoft.AspNetCore.Authentication.JwtBearer

یک کلید مخفی را در فایل appsettings.json مشخص کنید

بعد، بخشی را در فایل appsettings.json برای اطلاعات صادرکننده، مخاطب و کلید ایجاد کنید. این اطلاعات بعداً برای ایجاد یک توکن وب JSON استفاده خواهد شد. توجه داشته باشید که می توانید هر نامی را که می خواهید به این بخش بدهید. من از نام “Jwt” برای راحتی استفاده خواهم کرد.

پایتون برای حذف GIL و تقویت همزمانی حرکت می کند

اطلاعات زیر را به فایل appsettings.json اضافه کنید.

  "Jwt": {
    "Issuer": "https://joydipkanjilal.com/",
    "Audience": "https://joydipkanjilal.com/",
    "Key": "This is a sample secret key - please don't use in production environment.'"
  }

تنظیمات احراز هویت را در فایل Program.cs مشخص کنید

روش AddAuthenication در فایل Program.cs برای پیکربندی احراز هویت JWT در زمان شروع برنامه استفاده می شود. این طرح احراز هویت را به عنوان JwtBearer مشخص می کند. علاوه بر این، فراخوانی روش AddJwtBearer به پیکربندی پارامترهای نشانه کمک می کند.

مقادیر صادرکننده، مخاطب و کلید از فایل پیکربندی appsettings.json خوانده می‌شوند. نمونه TokenValidationParameters برای نشان دادن اینکه آیا اطلاعات صادرکننده، مخاطب، کلید و مادام العمر باید تأیید شوند یا خیر استفاده می‌شود.

builder.Services.AddAuthentication(options =>
    {
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(o =>
{
    o.TokenValidationParameters = new TokenValidationParameters
    {
        ValidIssuer = builder.Configuration["Jwt:Issuer"],
        ValidAudience = builder.Configuration["Jwt:Audience"],
        IssuerSigningKey = new SymmetricSecurityKey
        (Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])),
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidateLifetime = false,
        ValidateIssuerSigningKey = true
    };
});

برای افزودن خدمات مجوز به برنامه خود، Program.cs شما باید قطعه کد زیر را نیز شامل شود.

builder.Services.AddAuthorization();

Program.cs شما همچنین باید شامل روش‌های زیر برای فعال کردن قابلیت‌های احراز هویت و مجوز باشد.

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

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

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

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

این کلاس برای پذیرش اعتبار کاربری به عنوان ورودی استفاده خواهد شد.

یک نقطه پایانی برای تولید توکن های وب JSON ایجاد کنید

در نهایت، ما باید کد لازم را برای تولید و اعتبارسنجی JWT‌هایی که برای مجاز کردن تماس‌ها به API استفاده می‌کنیم، بنویسیم. هنگامی که یک نشانه در پاسخ به یک درخواست اولیه به API تولید می‌شود، می‌توانید آن را کپی کنید و از آن برای مجوز در تمام درخواست‌های بعدی استفاده کنید.

اکنون، کد زیر را در فایل Program.cs بنویسید تا یک نقطه پایانی HTTP Post جدید ایجاد کنید که یک JWT برای یک کاربر تأیید شده ایجاد می‌کند.

app.MapPost("/security/createToken",
[AllowAnonymous] (User user) =>
{
    if (user.UserName == "joydip" && user.Password == "joydip123")
    {
        var issuer = builder.Configuration["Jwt:Issuer"];
        var audience = builder.Configuration["Jwt:Audience"];
        var key = Encoding.ASCII.GetBytes
        (builder.Configuration["Jwt:Key"]);
        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(new[]
            {
                new Claim("Id", Guid.NewGuid().ToString()),
                new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
                new Claim(JwtRegisteredClaimNames.Email, user.UserName),
                new Claim(JwtRegisteredClaimNames.Jti,
                Guid.NewGuid().ToString())
            }),
            Expires = DateTime.UtcNow.AddMinutes(5),
            Issuer = issuer,
            Audience = audience,
            SigningCredentials = new SigningCredentials
            (new SymmetricSecurityKey(key),
            SecurityAlgorithms.HmacSha512Signature)
        };
        var tokenHandler = new JwtSecurityTokenHandler();         var token = tokenHandler.CreateToken(tokenDescriptor);         var jwtToken = tokenHandler.WriteToken(token);         var stringToken = tokenHandler.WriteToken(token);         return Results.Ok(stringToken);     }     return Results.Unauthorized(); });

یک نمونه از کلاس User برای پذیرش نام کاربری و رمز عبور ارسال شده به این نقطه پایانی استفاده می شود. به ویژگی AllowAnonymous توجه کنید. این برای مشخص کردن اینکه ما به بررسی مجوز در این نقطه پایانی نیازی نداریم استفاده می‌شود. صادرکننده، مخاطب و کلید از فایل پیکربندی خوانده می شوند. هر کدام از اینها برای ایجاد توکن استفاده می‌شود که مشخص کرده‌ایم تا پنج دقیقه دیگر منقضی می‌شود.

نحوه استفاده از دستورات جاوا اسکریپت در برنامه های خود

کد منبع کامل Program.cs

در اینجا کد منبع کامل فایل Program.cs برای مرجع شما آمده است.

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(o =>
{
    o.TokenValidationParameters = new TokenValidationParameters
    {
        ValidIssuer = builder.Configuration["Jwt:Issuer"],
        ValidAudience = builder.Configuration["Jwt:Audience"],
        IssuerSigningKey = new SymmetricSecurityKey
            (Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])),
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidateLifetime = false,
        ValidateIssuerSigningKey = true
    };
});
builder.Services.AddAuthorization();
var app = builder.Build();
app.UseHttpsRedirection();
app.MapGet("/security/getMessage", () => "Hello World!").RequireAuthorization();
app.MapPost("/security/createToken",
[AllowAnonymous] (User user) =>
{
    if (user.UserName == "joydip" && user.Password == "joydip123")
    {
        var issuer = builder.Configuration["Jwt:Issuer"];
        var audience = builder.Configuration["Jwt:Audience"];
        var key = Encoding.ASCII.GetBytes
        (builder.Configuration["Jwt:Key"]);
        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(new[]
            {
                new Claim("Id", Guid.NewGuid().ToString()),
                new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
                new Claim(JwtRegisteredClaimNames.Email, user.UserName),
                new Claim(JwtRegisteredClaimNames.Jti,
                Guid.NewGuid().ToString())
             }),
            Expires = DateTime.UtcNow.AddMinutes(5),
            Issuer = issuer,
            Audience = audience,
            SigningCredentials = new SigningCredentials
            (new SymmetricSecurityKey(key),
            SecurityAlgorithms.HmacSha512Signature)
        };
        var tokenHandler = new JwtSecurityTokenHandler();
        var token = tokenHandler.CreateToken(tokenDescriptor);
        var jwtToken = tokenHandler.WriteToken(token);
        var stringToken = tokenHandler.WriteToken(token);
        return Results.Ok(stringToken);
    }
    return Results.Unauthorized();
});
app.UseAuthentication();
app.UseAuthorization();
app.Run();

احراز هویت JWT در عمل

وقتی اعتبار کاربر را با استفاده از Postman در نقطه پایانی createToken پست می‌کنید، می‌توانید کد تولید شده را ببینید.

secure minimal api 02

شکل ۲. JWT با موفقیت تولید شد.

توجه داشته باشید که ما اعتبار کاربری، یعنی نام کاربری و رمز عبور را در متن درخواست ارسال کرده‌ایم.

اکنون، نقطه پایانی HTTP Get را که قبلا ایجاد کرده بودیم فراخوانی کنید و توکن تولید شده را به عنوان نشانه حامل در هدر درخواست ارسال کنید. اگر توکن تولید شده شما معتبر باشد، پیام نشان داده شده در شکل ۳ را مشاهده خواهید کرد.

secure minimal api 03

شکل ۳. نقطه پایانی HTTP Get پیام متنی در پاسخ را برمی‌گرداند.

همانطور که در شکل ۳ مشاهده می کنید، پیام متنی “Hello World!” نمایش داده می شود زیرا رمزی که ما ارسال کردیم معتبر است. به پاسخ HTTP 200 OK نیز توجه کنید (در یک مستطیل سبز برجسته شده است).

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

برای آزمایش حداقل پیاده‌سازی API خود در اینجا، از Postman استفاده کرده‌ایم، یکی از محبوب‌ترین ابزارهای موجود امروز برای آزمایش API ها. برای آزمایش حداقل نقاط پایانی API خود، می‌توانید از Swagger نیز استفاده کنید، یک جعبه ابزار که ارائه یک نمایش گرافیکی از API شما را ساده می‌کند.