JSON Web Token در ASP.NET Core

JSON Web Token در ASP.NET Core

JSON Web Token (نشانه ی وب JSON) بیشتر در توسعه ی وب مشهور می شود. یک استاندارد باز است که انتقال داده ها بین بخش ها به عنوان یک شیء JSON را به شیوه ای امن و بهم پیوسته فراهم می کند.

انتقال داده ها با استفاده از JSON Web Token  بین بخش ها بصورت دیجیتالی علامت گذاری می شود تا به آسانی اعتبارسنجی شده و مورد اعتماد باشد.
در این مقاله، نحوه ی راه اندازی JWT با ASP.NET core web application را خواهیم آموخت.

می توانیم برنامه ای با استفاده از ویژوال استودیو یا CLI (رابط خط فرمان) ایجاد کنیم.

JSON Web Token

dotnet new webapi -n JWTAuthentication  

فرمان فوق، یک پروژه ی ASP.NET Web API با نام “JWTAuthentication” در پوشه ی فعلی ایجاد خواهد کرد.

مرحله ی اول، پیکربندی احراز هویت مبتنی بر JSON Web Token در پروژه مان است.

برای این کار، نیاز است که شما/طرح احراز هویت JWT را با استفاده از متد “AddAuthentication” و مشخص کردن JwtBearerDefaults.AuthenticationSchema ثبت کنیم.

در اینجا، طرح احراز هویت را با امکانات حامل JWT پیکربندی می کنیم.

public void ConfigureServices(IServiceCollection services)  
{  
    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)  
    .AddJwtBearer(options =>  
    {  
        options.TokenValidationParameters = new TokenValidationParameters  
        {  
            ValidateIssuer = true,  
            ValidateAudience = true,  
            ValidateLifetime = true,  
            ValidateIssuerSigningKey = true,  
            ValidIssuer = Configuration["Jwt:Issuer"],  
            ValidAudience = Configuration["Jwt:Issuer"],  
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))  
        };  
    });  
    services.AddMvc();  
}  

در این مثال، مشخص کرده ایم که کدام پارامترها باید برای اینکه JWT معتبر شناخته شود، مد نظر قرار بگیرند. طبق کد ما، آیتم های زیر یک نشانه را معتبر می شناسند:

  •  اعتبارسنجی سروری (ValidateIssuer = true) که نشانه را تولید می کند.
  •  اعتبارسنجی اینکه گیرنده ی نشانه برای دریافت تأیید شده باشد (ValidateAudience = true).
  • بررسی اینکه نشانه منقضی نشده باشد و کلید علامت گذاری صادرکننده معتبر باشد (ValidateLifetime = true).
  • اعتبارسنجی علامت گذاری نشانه (ValidateIssuerSigningKey = true).
  • بعلاوه، مقادیر صادرکننده، مخاطبان و کلید علامت گذاری را مشخص می کنیم. در این مثال، این مقادیر را در فایل appsettings.json ذخیره کرده ام.

AppSettings.Json

{  
  "Jwt": {  
    "Key": "ThisismySecretKey",  
    "Issuer": "Test.com"  
  }  
}    

مراحل ذکر شده ی فوق جهت پیکربندی سرویس احراز هویت مبتنی بر JWT استفاده می شوند.

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

برای این کار، نیاز است متد app.UseAuthentication() در متد Configure از کلاس Startup را فراخوانی کنیم. متد UseAthentication پیش از متد UseMvc فراخوانی می شود.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)  
{  
    app.UseAuthentication();  
    app.UseMvc();  
}  

تولید JSON Web Token

من یک LoginController و متد Login درون این کنترل کننده ایجاد کرده ام، که مسئول تولید JSON Web Token است.

این متد را با صفت AllowAnonymous نشانه گذاری کرده ام تا از احراز هویت عبور کند.

این متد منتظر شیء UserModel برای Username و Password است.

متد “AuthenticateUser” را ایجاد کرده ام، که مسئول اعتبارسنجی اعتبارنامه ی کاربر و بازگشت ها به UserModel است.

برای اهداف نمایشی، مدل کد اختصاصی (hardcode model) را بازگردانده ام اگر نام کاربری “Jignesh” بوده باشد.

اگر متد “AuthenticateUser” مدل کاربری را بازگرداند، API نشانه ی جدید را با استفاده از متد “GenerateJSONWebToken” تولید می کند.
در اینجا، یک JWT با استفاده از کلاس JwtSecurityToken ایجاد کرده ام.

یک شیء از این کلاس را از طریق ارسال برخی پارامترها به سازنده، مانند صادرکننده، مخاطبان، انقضاء، و نشانه گذاری/امضا، ایجاد کرده ام.
در آخر، متد JwtSecurityTokenHandler.WriteToken برای تولید JWT استفاده شده است. این متد منتظر شیء کلاس JwtSecurityToken است.

using Microsoft.AspNetCore.Authorization;  
using Microsoft.AspNetCore.Mvc;  
using Microsoft.Extensions.Configuration;  
using Microsoft.IdentityModel.Tokens;  
using System;  
using System.IdentityModel.Tokens.Jwt;  
using System.Security.Claims;  
using System.Text;  
  
namespace JWTAuthentication.Controllers  
{  
    [Route("api/[controller]")]  
    [ApiController]  
    public class LoginController : Controller  
    {  
        private IConfiguration _config;  
  
        public LoginController(IConfiguration config)  
        {  
            _config = config;  
        }  
        [AllowAnonymous]  
        [HttpPost]  
        public IActionResult Login([FromBody]UserModel login)  
        {  
            IActionResult response = Unauthorized();  
            var user = AuthenticateUser(login);  
  
            if (user != null)  
            {  
                var tokenString = GenerateJSONWebToken(user);  
                response = Ok(new { token = tokenString });  
            }  
  
            return response;  
        }  
  
        private string GenerateJSONWebToken(UserModel userInfo)  
        {  
            var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));  
            var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);  
  
            var token = new JwtSecurityToken(_config["Jwt:Issuer"],  
              _config["Jwt:Issuer"],  
              null,  
              expires: DateTime.Now.AddMinutes(120),  
              signingCredentials: credentials);  
  
            return new JwtSecurityTokenHandler().WriteToken(token);  
        }  
  
        private UserModel AuthenticateUser(UserModel login)  
        {  
            UserModel user = null;  
  
            //Validate the User Credentials  
            //Demo Purpose, I have Passed HardCoded User Information  
            if (user.Username == "Jignesh")  
            {  
                user = new UserModel { Username = "Jignesh Trivedi", EmailAddress = "test.btest@gmail.com" };  
            }  
            return user;  
        }  
    }  
}   

هنگامیکه احراز هویت مبتنی بر JSON Web Token را فعال کردیم، یک متد Web API ساده ایجاد کرده ام که لیستی از رشته های مقدار را، هنگامیکه با یک درخواست HTTP GET فراخوانی شود، بازمی گرداند.

در اینجا، این متد را با صفت تأیید (authorize) نشانه گذاری کرده ام، تا این نقطه ی پایانی، بررسی اعتبارسنجی نشانه ی ارسال شده با درخواست HTTP را تحریک کند.
اگر این متد را بدون نشانه فراخوانی کنیم، کد وضعیت HTTP ِ ۴۰۱ [ دسترسی تأیید نشده ] را به عنوان پاسخ دریافت خواهیم کرد.

اگر بخواهیم از احراز هویت برای هر متدی عبور کنیم، می توانیم آن متد را با صفت AllowAnonymous نشانه گذاری کنیم.

جهت آزمودن Web API ایجاد شده، از Fiddler استفاده می کنیم. نخست، به متد “API/login” برای تولید نشانه درخواست داده ام.

JSON زیر را در بدنه ی درخواست ارسال کرده ام.

{"username": "Jignesh", "password": "password"}  

JSON Web Token

به عنوان پاسخ، JSON را مانند تصویر زیر دریافت خواهیم کرد،

{  
    "token" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJKaWduZXNoIFRyaXZlZGkiLCJlbWFpbCI6InRlc3QuYnRlc3RAZ21haWwuY29tIiwiRGF0ZU9mSm9pbmciOiIwMDAxLTAxLTAxIiwianRpIjoiYzJkNTZjNzQtZTc3Yy00ZmUxLTgyYzAtMzlhYjhmNzFmYzUzIiwiZXhwIjoxNTMyMzU2NjY5LCJpc3MiOiJUZXN0LmNvbSIsImF1ZCI6IlRlc3QuY29tIn0.8hwQ3H9V8mdNYrFZSjbCpWSyR1CNyDYHcGf6GqqCGnY"  
}  

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

در ادامه تعریف متد Action من آمده است.

[HttpGet]  
[Authorize]  
public ActionResult<IEnumerable<string>> Get()  
{  
    return new string[] { "value1", "value2", "value3", "value4", "value5" };  
}  
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJKaWduZXNoIFRyaXZlZGkiLCJlbWFpbCI6InRlc3QuYnRlc3RAZ21haWwuY29tIiwiRGF0ZU9mSm9pbmciOiIwMDAxLTAxLTAxIiwianRpIjoiYzJkNTZjNzQtZTc3Yy00ZmUxLTgyYzAtMzlhYjhmNzFmYzUzIiwiZXhwIjoxNTMyMzU2NjY5LCJpc3MiOiJUZXN0LmNvbSIsImF1ZCI6IlRlc3QuY29tIn0.8hwQ3H9V8mdNYrFZSjbCpWSyR1CNyDYHcGf6GqqCGnY  

JSON Web Token

مدیریت Claims با JSON Web Token

Claims داده هایی هستند که توسط نشانه در بر گرفته می شوند.

اطلاعاتی در رابطه با کاربر هستند که به ما در تأیید دسترسی به یک منبع کمک می کنند.

می توانند نام کاربری، نشانی پست الکترونیکی، نقش یا هر اطلاعات دیگری باشند.

می توانیم اطلاعات claims را به JSON Web Token اضافه کنیم تا هنگام بررسی جهت تأیید موجود باشند.

در مثال فوق، اگر بخواهیم claims را به نشانه ی خود ارسال کنیم، نیاز است اطلاعات claims متد GenerateJSONWebToken از کنترل کننده ی Login را اضافه کنند.

در مثال زیر، یک نام کاربری، نشانی پست الکترونیکی، و تاریخ پیوستن/عضو شدن را که به نشانه claim شده اند اضافه کرده ام.

private string GenerateJSONWebToken(UserModel userInfo)  
{  
    var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));  
    var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);  
  
    var claims = new[] {  
        new Claim(JwtRegisteredClaimNames.Sub, userInfo.Username),  
        new Claim(JwtRegisteredClaimNames.Email, userInfo.EmailAddress),  
        new Claim("DateOfJoing", userInfo.DateOfJoing.ToString("yyyy-MM-dd")),  
        new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())  
    };  
  
    var token = new JwtSecurityToken(_config["Jwt:Issuer"],  
        _config["Jwt:Issuer"],  
        claims,  
        expires: DateTime.Now.AddMinutes(120),  
        signingCredentials: credentials);  
  
    return new JwtSecurityTokenHandler().WriteToken(token);  
}

claims آرایه ای از جفت کلید مقدار هستند.

کلیدها ممکن است مقادیر یک ساختار JwtRegisteredClaimNames (نام هایی برای claimهای استاندارد شده ی عمومی ارائه می کند) یا نام دلخواه (مانند DateOfJoining در مثال فوق) باشند.
این claims می تواند برای فیلتر کردن داده ها بکار رود.

در مثال زیر، باید لیست مقادیر را، اگر کاربر بیش از ۵ سال با شرکت بگذراند، تغییر دهم.

 [HttpGet]  
[Authorize]  
public ActionResult<IEnumerable<string>> Get()  
{  
    var currentUser = HttpContext.User;  
    int spendingTimeWithCompany = 0;  
  
    if (currentUser.HasClaim(c => c.Type == "DateOfJoing"))  
    {  
        DateTime date = DateTime.Parse(currentUser.Claims.FirstOrDefault(c => c.Type == "DateOfJoing").Value);  
        spendingTimeWithCompany = DateTime.Today.Year - date.Year;  
    }  
  
    if(spendingTimeWithCompany > 5)  
    {  
        return new string[] { "High Time1", "High Time2", "High Time3", "High Time4", "High Time5" };  
    }  
    else  
    {  
        return new string[] { "value1", "value2", "value3", "value4", "value5" };  
    }  
}

خلاصه

JSON Web Token در توسعه ی وب بسیار مشهور است.

یک استاندارد باز است که انتقال داده ها بین بخش ها را به عنوان یک شیء JSON به شیوه ای امن و فشرده فراهم می کند.

در این مقاله، نحوه ی تولید و استفاده از JWT با برنامه ی ASP.NET Core را خواهیم آموخت.

می توانید سورس کد/source code را از لینک GitHub در اینجا دیده یا دانلود کنید.


زهره سلطانیان

نوشته‌های مرتبط

دیدگاه‌ها

*
*

این سایت از اکیسمت برای کاهش هرزنامه استفاده می کند. بیاموزید که چگونه اطلاعات دیدگاه های شما پردازش می‌شوند.