پیاده سازی احراز هویت JWT در net 5 Web API.

آخرین بروز رسانی: 1401/02/14

در این مقاله یک فرآیند کامل گام به گام برای پیاده سازی Authentication در Asp.net Core Web API با استفاده از JSON Web Token یا همون JWT رو یادمیگیریم. ما باید اطمینان حاصل کنیم که API های ما هنگام توسعه آنها محافظت و ایمن هستند.

یعنی باید یک کاربر را احراز هویت کنیم تا فقط کاربران معتبر بتوانند APIS ما را استفاده کنند. با استفاده از JWT می توانیم به راحتی احراز هویت مبتنی بر توکن را در Asp.net Core پیاده سازی کنیم و از برنامه خود محافظت کنیم. همچنین به محض منقضی شدن توکن ، نحوه رفرش توکن JWT در برنامه Asp.net Core را بررسی کنید.

 

JSON Web Token چیست؟

با توجه به متن RFC 7519  ,  JWT یک تکنیک باز و استاندارد صنعتی برای انتقال امن دسترسیها بین دو طرف است. این بدان معنی است که داده های ارسال شده بین دو طرف با استفاده از JWT به صورت دیجیتال امضا شده است و به راحتی قابل تایید و اعتماد است.

 

به طور خلاصه، با استفاده از JWT می‌توانیم احراز هویت(Authentication) و مجوز(Authorization) را در هر برنامه وب با هر تکنولوژی مانند Asp.net Core، Java، NodeJs، Python و غیره پیاده‌سازی کنیم.

مراحل پیاده سازی JWT Authentication در Asp.net Core

  • آشنایی با گردش کار احراز هویت JWT.
  • پروژه net Core Web API را ایجاد کنید
  • بسته NuGet (JwtBearer) را نصب کنید
  • پیکربندی net Core JWT appsetting.json
  • net Core Startup.cs - سرویس ها را پیکربندی کنید JwtBearer را اضافه کنید
  • مدل‌ کاربر ، توکن‌ها را ایجاد کنید
  • برای احراز هویت کاربران و تولید JSON Web Token، JWTManagerRepository ایجاد کنید.
  • ایجاد UserController - روش عمل احراز هویت.

 

# آشنایی با گردش کار احراز هویت JWT.

در اینجا در تصویر زیر، نمودار جریان JWT Authentication را در Asp.net Core Web API نشان می‌دهیم.

 

# پروژه Asp.net Core Web API را ایجاد کنید

در اینجا ابتدا پروژه Asp.net Core web API را با استفاده از نسخه Asp.net Core 5 ایجاد می‌کنیم، اگر می‌خواهید می‌توانید نسخه پایین‌تر یعنی Asp.net Core 3.1 را نیز انتخاب کنید.

 

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

دو بسته NuGet که برای اجرای احراز هویت JWT در برنامه Asp.net Core نیاز داریم، Microsoft.AspNetCore.Authentication.JwtBearer و System.IdentityModel.Tokens.Jwt هستند.

# پیکربندی Asp.net Core JWT appsetting.json

پس از نصب بسته‌های NuGet، سپس فایل appsetting.json خود را تغییر داده و کلید مخفی و مقادیر دیگر را اضافه می‌کنیم. هنگام تولید JSON Web Token به این مقادیر بیشتر نیاز داشتیم.

 

فایل appsetting.json ما شبیه چیزی است که در زیر نوشته شده است:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "JWT": {
    "Key": "This is my supper secret key for jwt",
    "Issuer": "https://redmask.ir",
    "Audience": " redmask.ir"
  }
}

در اینجا ما عنصر ریشه جدید JWT را اضافه کردیم و دارای 3 مقدار است یعنی کلید، صادرکننده، مخاطب.

 

# Asp.net Core Startup.cs - پیکربندی خدمات اضافه کردن JwtBearer

در برنامه Asp.net Core فایل Startup.cs نقطه ورود برنامه است. این به ما امکان می دهد پیکربندی را بارگیری کنیم، خدمات وابستگی را ثبت کنیم و ترتیب خط لوله درخواست(request pipeline) را تنظیم کنیم.

 

در متد Configure، میان افزار(همون middleware) UseAuthentication() را قبل از UseAuthorization() اضافه می کنیم. همچنین در متد, ConfigureServices AddAuthentication رو با AddJwtBearer پیکربندی می کنیم.

کد فایل Startup.cs ما مانند زیر است:

public void ConfigureServices(IServiceCollection services)
{
	services.AddAuthentication(x =>
	{
		x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
		x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
	}).AddJwtBearer(o =>
	{
		var Key = Encoding.UTF8.GetBytes(Configuration["JWT:Key"]);
		o.SaveToken = true;
		o.TokenValidationParameters = new TokenValidationParameters
		{
			ValidateIssuer = false,
			ValidateAudience = false,
			ValidateLifetime = true,
			ValidateIssuerSigningKey = true,
			ValidIssuer = Configuration["JWT:Issuer"],
			ValidAudience = Configuration["JWT:Audience"],
			IssuerSigningKey = new SymmetricSecurityKey(Key)
		};
	});

	services.AddSingleton<IJWTManagerRepository, JWTManagerRepository>();

	services.AddControllers();
}

در اینجا با استفاده از Configuration["JWT:Key"] کلید مخفی را از فایل appsetting.json خود دریافت می کنیم.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
	if (env.IsDevelopment())
	{
		app.UseDeveloperExceptionPage();
	}

	app.UseHttpsRedirection();
	app.UseRouting();

	app.UseAuthentication(); // This need to be added	
	app.UseAuthorization();
	app.UseEndpoints(endpoints =>
	{
	    endpoints.MapControllers();
	});
}

توجه 💡: در فایل Startup.cs باید 2 فضای نام مانند Microsoft.IdentityModel.Tokens و Microsoft.AspNetCore.Authentication.JwtBearer را وارد کنیم.

 

# کاربران مدل‌ها، توکن‌ها را ایجاد کنید

حالا یک پوشه جدید به نام Models اضافه می کنیم و دو کلاس جدید به نام Users, Token اضافه می کنیم. کدهای فایل هر دو کلاس ما به شکل زیر هستند.

public class Users
{
	public string Name { get; set; }
	public string Password { get; set; }
}
public class Tokens
{
	public string Token { get; set; }
	public string RefreshToken { get; set; }
}

 

# یک اینترفیس IJWTManagerRepository برای احراز هویت کاربران و تولید JWT ایجاد کنید.

اکنون یک پوشه جدید به نام Repository ایجاد می کنیم که در زیر آن یک رابط جدید به عنوان IJWTManagerRepository ایجاد می کنیم.

در اینترفیس IJWTManagerRepository یک متد Authenticate(Users u) اضافه می کنیم که یک توکن JWT معتبر برمی گرداند. کد فایل IJWTManagerRepository.cs ما مانند زیر است:

using JWTWebAuthentication.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace JWTWebAuthentication.Repository
{
   public interface IJWTManagerRepository
    {
        Tokens Authenticate(Users users); 
    }  
}

حالا کلاس جدید به نام JWTManagerRepository.cs ایجاد می کنیم که از اینترفیس IJWTManagerRepository ارثبری می کنه

در اینجا ما Dictionary را به عنوان UsersRecords اضافه می کنیم که حاوی رکورد کاربر ما است. شما می توانید این کار را با یک دیتابیس انجام بدید، الان تمرکز اصلی ما اجرای JWT است، بنابراین من از دیکشنری با رکوردهای تستی استفاده می کنیم.

کد نهایی ما به شکل زیر نوشته شده است:

public class JWTManagerRepository : IJWTManagerRepository
{
	Dictionary<string, string> UsersRecords = new Dictionary<string, string>
	{
		{ "user1","password1"},
		{ "user2","password2"},
		{ "user3","password3"},
	};

	private readonly IConfiguration iconfiguration;
	public JWTManagerRepository(IConfiguration iconfiguration)
	{
		this.iconfiguration = iconfiguration;
	}
	public Tokens Authenticate(Users users)
	{
		if (!UsersRecords.Any(x => x.Key == users.Name && x.Value == users.Password)) {
			return null;
		}

		// Else we generate JSON Web Token
		var tokenHandler = new JwtSecurityTokenHandler();
		var tokenKey = Encoding.UTF8.GetBytes(iconfiguration["JWT:Key"]);
		var tokenDescriptor = new SecurityTokenDescriptor
		{
		  Subject = new ClaimsIdentity(new Claim[]
		  {
			 new Claim(ClaimTypes.Name, users.Name)                    
		  }),
		   Expires = DateTime.UtcNow.AddMinutes(10),
		   SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(tokenKey),SecurityAlgorithms.HmacSha256Signature)
		};
		var token = tokenHandler.CreateToken(tokenDescriptor);
		return new Tokens { Token = tokenHandler.WriteToken(token) };

	}
}

در اینجا ابتدا بررسی می کنیم که آیا کاربر معتبر است یا خیر. اگر کاربر معتبر نباشد، null را برمی‌گردانیم، در غیر این صورت، JSON Web Token را تولید می‌کنیم و شی کلاس Tokens را برمی‌گردانیم.

هنگام استفاده از توکن JWT، مجوزها(authorizations) بر اساس claimهای موجود در توکن JWT است.

برای تنظیم زمان انقضای توکن JWT در Asp.net Core، از پارامتر Expires در SecurityTokenDescriptor استفاده می کنیم و مقدار آن را به عنوان هر چیزی که می خواهیم تنظیم می کنیم. ما می‌توانیم از .AddMinutes() برای تنظیم انقضای توکن JWT در چند دقیقه یا .AddHours برای تنظیم انقضای نشانه JWT در ساعت استفاده کنیم.

در اینجا در کد بالا، زمان انقضای توکن JWT را 10 دقیقه تعیین می کنیم، بنابراین پس از 10 دقیقه، توکن نامعتبر می شود.

توجه: ما باید سرویس IJWTManagerRepository را در متد ConfigureServices در فایل Startup.cs  ثبت کنیم.

 

#Create UserController - روش عمل احراز هویت

در پوشه Controllers یک کنترلر جدید به نام UsersController اضافه می کنیم و در سازنده آن رابط IJWTManagerRepository را تزریق می کنیم.

UsersController دو Action داره که یکی برای احراز هویت کاربر و در پاسخ گرفتن JWT است. و دیگری برای نمایش لیست کاربران تنها در صورتی که کاربر با استفاده از JWT احراز هویت شده باشد.

[Authorize]
[Route("api/[controller]")]
[ApiController]  
public class UsersController : ControllerBase
{
	private readonly IJWTManagerRepository _jWTManager;

	public UsersController(IJWTManagerRepository jWTManager)
	{
		this._jWTManager = jWTManager;
	}

	[HttpGet]
	public List<string> Get()
	{
		var users = new List<string>
		{
			"Satinder Singh",
			"Amit Sarna",
			"Davin Jon"
		};

		return users;
	}

	[AllowAnonymous]
	[HttpPost]
	[Route("authenticate")]
	public IActionResult Authenticate(Users usersdata)
	{
		var token = _jWTManager.Authenticate(usersdata);

		if (token == null)
		{
			return Unauthorized();
		}

		return Ok(token);
	}
}

در اینجا، در سطح کنترل‌کننده، ما با ویژگی [Authorize] تزئین کردیم تا اطمینان حاصل کنیم که هیچ روش عملی بدون احراز هویت فراخوانی نمی‌شود.

به طور مشابه، در متدAuthenticate  را با ویژگی [AllowAnonymous] تزئین کردیم که ویژگی [Authorize] را لغو می کند. این اجازه می دهد تا همه کاربران به متد Authenticate دسترسی داشته باشند، که در صورت قانونی بودن کاربر، JWT را برمی گرداند.

ویژگی [Authorize] مسئول اعتبار سنجی توکن در برابر قوانین تعریف شده در متد Startup.cs ConfigureServices است.

 

#تست عملکرد با استفاده از نرمافزار postman

حالا بیاید API رو با Postman تست کنیم.

ابتدا Get request را فراخوانی می کنیم تا بررسی کنیم که آیا می توانیم لیست کاربران را بدون هیچ گونه احراز هویت نمایش دهیم.

همانطور که در شکل 1 در پاسخ به عنوان 401 غیر مجاز برمی گردد

 

در مرحله بعد ما احراز هویت API را با اعتبار کاربری معتبر فراخوانی می کنیم. همانطور که در شکل 2 در پاسخ، توکن JWT را دریافت کردیم که در هدر برای احراز هویت استفاده کردیم.

 

حالا دوباره متد Get را فراخوانی می کنیم، اما با توکن معتبری که در فراخوانی قبلی ایجاد کرده بودیم. همانطور که در شکل 3 ما می توانیم داده های کاربر را پس از احراز هویت مناسب با استفاده از JSON Web Token نمایش دهیم.

 

 

 

 

دیکود کردن JWT

 

 

نظر دهید

آدرس ایمیل شما منتشر نخواهد شد. فیلدهای الزامی علامت گذاری شده اند *