امروزه استفاده از claim به یک ترند جهانی تبدیل شده است و بسیاری از افراد از آن استفاده می‌کنند. شاید شما نیز نام claim را نخستین بار در آموزش authentication در MVC شنیده باشید. در authentication، ما مفهومی به نام claim base identity داریم که در حقیقت با استفاده از آن می‌توان امنیت identity را تامین کرد و فرایند احراز هویت امن‌تری برای ما ایجاد کرد. در این مقاله به صورت کامل با claim آشنا می‌شوید و می‌توانیم با استفاده از یک مثال عملی روش کار آن را ببینیم.

آموزش claim در mvc
آموزش claim در mvc

Identity چیست؟

Identity یکی از سیستم‌های احراز هویت است که پس از سیستم‌هایی همچون ASP.NET Membership و Simple Membership برای ASP.NET MVC معرفی شده است. claim base identity نیز به نوعی یکی از attribute های identity است که به ما برای احراز هویت امن‌تر کمک می‌کند.

نکته
مقاله پیشنهادی: آموزش identity در mvc

Claim چیست؟

Claim در حقیقت اعطای اعتبار دسترسی به بخشی از سایت یا اپلیکیشن تحت وب ما، پس از دریافت اطلاعاتی از کاربر است. بهتراست claim را با استفاده از یک مثال توضیح دهیم. ممکن است برای شما نیز پیش آمده باشد که وارد سایتی شوید و این سایت برای ثبت نام شما اطلاعاتی را از شما درخواست کند. این اطلاعات می‌تواند شهر محل زندگی، کشور محل زندگی و یا تاریخ تولد شما و اطلاعات دیگری باشد. مورد مهم اما این است که برنامه‌نویس سایت قانونی مبنی بر اینکه فقط افراد چند کشور مشخص، توانایی استفاده از این سایت را دارند گذاشته باشد. پس از این اتفاق داده‌های دریافت شده از شما بررسی می‌شود و برای نمونه اگر کشور شما با کشورهای مجاز که در درون سایت وجود دارند همخوانی نداشت. اجازه دسترسی شما به محتوای سایت گرفته می‌شود. این دقیقاً مثالی از claim و روش کار آن است.

claim چیست؟
claim چیست؟

نحوه استفاده از claim در MVC

در اینجا می‌خواهیم از claim در ASP.NET MVC استفاده کنیم و ببینیم که claim base security چگونه و به چه شکلی به کمک ما میاید. برای این کار ابتدا یک پروژه hello world به صورت ASP.NET MVC Web application در ویژوال استودیو ایجاد کنید. پروژه ایجاد شده به طور خودکار تمام تنظیمات و قابلیت‌هایی که ما به آن نیاز داریم را برای ما اضافه می‌کند. تنها کاری که ما باید انجام دهیم و برای ما لازم است. افزودن یک claim در مراحل ثبت نام و احراز هویت کاربران است. پس از این کار نیز محدودیت‌هایی را بر پایه اطلاعات دریافت کرده، برای کاربران لحاظ می‌کنیم.

ابتدا و به سرعت به تاکید بر عملکرد قسمت‌هایی مهمی که کارهای امنیتی را انجام می‌دهند می‌پردازیم:

App_Start/Startup.Auth.cs کلاسی برای امنیت bootstrapping است.

1.	public void ConfigureAuth(IAppBuilder app)
2.	   {
3.	       / /Configure the db context, user manager, and signin
4.	       / /manager to use a single instance per request
5.	      app.CreatePerOwinContext(ApplicationDbContext.Create);
6.	      app.CreatePerOwinContext<ApplicationUserManager>
7.	         (ApplicationUserManager.Create);
8.	      app.CreatePerOwinContext<ApplicationSignInManager>
9.	         (ApplicationSignInManager.Create);
10.	 
11.	       / /Enable the application to use a cookie to store
12.	       / /information for the signed-in user and to use
13.	       / /a cookie to temporarily store information about
14.	       / /a user logging in with a third-party login provider
15.	       / /Configure the sign-in cookie
16.	      app.UseCookieAuthentication(new CookieAuthenticationOptions
17.	      {
18.	         AuthenticationType = DefaultAuthenticationTypes.
19.	            ApplicationCookie,
20.	         LoginPath = new PathString("/Account/Login"),
21.	         Provider = new CookieAuthenticationProvider
22.	         {
23.	             / /Enables the application to validate the security
24.	             / /stamp when the user logs in.
25.	             / /This is a security feature that is used when you
26.	             / /change a password or add an external login to
27.	             / /your account.
28.	            OnValidateIdentity = SecurityStampValidator.
29.	               OnValidateIdentity<ApplicationUserManager,
30.	               ApplicationUser>(
31.	               validateInterval: TimeSpan.FromMinutes(30),
32.	               regenerateIdentity: (manager, user) =>
33.	                 user.GenerateUserIdentityAsync(manager))
34.	            }
35.	      });
36.	      app.UseExternalSignInCookie(DefaultAuthenticationTypes.
37.	                                  ExternalCookie);
38.	 
39.	       / /Enables the application to temporarily store user
40.	       / /information when they are verifying the second factor
41.	       / /in the two-factor authentication process.
42.	      app.UseTwoFactorSignInCookie
43.	         (DefaultAuthenticationTypes.TwoFactorCookie,
44.	          TimeSpan.FromMinutes(5));
45.	 
46.	       / /Enables the application to remember the second login
47.	       / /verification factor, such as phone or email.
48.	       / /Once you check this option, your second step of
49.	       / /verification during the login process will be
50.	       / /remembered on the device from where you logged in.
51.	       / /This is similar to the RememberMe option when you
52.	       / /log in.
53.	      app.UseTwoFactorRememberBrowserCookie
54.	         (DefaultAuthenticationTypes.
55.	          TwoFactorRememberBrowserCookie);
56.	   }

 App_Start/IdentityConfig.cs تنظیمات و افزونههای identity است.

 Models/IdentityModels.cs حاوی کلاس ApplicationUser است.

1.	public class ApplicationUser : IdentityUser
2.	   {
3.	      public async Task<ClaimsIdentity> GenerateUserIdentityAsync
4.	         (UserManager<ApplicationUser> manager)
5.	      {
6.	          / /Note the authenticationType must match the one defined
7.	          / /in CookieAuthenticationOptions.AuthenticationType
8.	         var userIdentity = await manager.CreateIdentityAsync(this,
9.	            DefaultAuthenticationTypes.ApplicationCookie);
10.	          / /Add custom user claims here
11.	         return userIdentity;
12.	      }
13.	   }

اینجا مکانی است که به واسطه آن می‌توانیم تعدادی claim را معرفی کرده و از آنها استفاده کنیم. برای این کار بهتر است از تغییر کدها به شکل قابل استفاده در دنیای واقعی آغاز کنیم.

  1. Enable Entity Framework Migrations

فعال سازی entity framework migration به ما کمک می‌کند تا در صورت وجود داده‌های تکراری، الگوی دیتابیس ما به هم نریزد. پس استفاده از آن برای ما و در هنگام استفاده از claim در دنیای واقعی مهم است.

  1. Add Relevant Properties

اضافه کردن properties در کلاس application user انجام می‌شود و پس از آن می‌توان اطلاعات claim که properties آن را مشخص کردیم استفاده کرد. بیایید BirthDate را گرفته و به عنوان property به application user اضافه کنیم.

  1. Add EF Migration

یک EF migration به فیلد جدید دیتابیس به روز شده خود، در packet manager console اضافه می‌کنیم.

با استفاده از Add-Migration به شکل Age’ <press enter> می‌توانیم یک اسکریپت آپدیت شده برای تغییرات خود اضافه کنیم.

حال Update-Database <press enter> را انجام دهید تا بتوانید الگو database را آپدیت کنید.

  1. Add the Birthday Value

اکنون جایی است که مقادیر تاریخ تولد را به فرم کاربر وارد می‌کنیم. برای این کار اعداد تولد را در فرم ثبت نام کاربر و در آدرس Models\AccountViewModels.cs RegisterViewModel class قرار می‌دهیم.

1.	public class RegisterViewModel
2.	   {
3.	      [Required]
4.	      [EmailAddress]
5.	      [Display(Name = "Email")]
6.	      public string Email { get; set; }
7.	 
8.	      [Required]
9.	      [StringLength(100, ErrorMessage = "The {0}
10.	         must be at least {2} characters long.",
11.	         MinimumLength = 6)]
12.	      [DataType(DataType.Password)]
13.	      [Display(Name = "Password")]
14.	      public string Password { get; set; }
15.	 
16.	      [DataType(DataType.Password)]
17.	      [Display(Name = "Confirm password")]
18.	      [Compare("Password", ErrorMessage =
19.	         "The password and confirmation password do
20.	         not match.")]
21.	      public string ConfirmPassword { get; set; }
22.	 
23.	      [Required]
24.	      [Display(Name ="Date of Birth")]
25.	      [DataType(DataType.Date)]
26.	      public DateTime BirthDate { get; set; }
27.	   }

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

  1. Update the Views\Account\Register.cshtml File

فایل Views\Account\Register.cshtml را با افزودن یک فیلد جدید به روز می‌کنیم.

1.	...
2.	   <div class="form-group">
3.	      @Html.LabelFor(m => m.BirthDate, new
4.	         { @class = "col-md-2 control-label" })
5.	      <div class="col-md-10">
6.	         @Html.TextBoxFor(m => m.BirthDate, new
7.	            { @class = "form-control" })
8.	      </div>
9.	   </div>
10.	...
ثبت نام حساب جدید
ثبت نام حساب جدید
  1. Update the Controllers\AccountController.cs Register Method

روش رجیستر Controllers\AccountController.cs را برای رد شدن از تولد به روز می‌کنیم.

1.	    / /POST: /Account/Register
2.	   [HttpPost]
3.	   [AllowAnonymous]
4.	   [ValidateAntiForgeryToken]
5.	   public async Task<ActionResult> Register(RegisterViewModel model)
6.	   {
7.	      if (ModelState.IsValid)
8.	      {
9.	         var user = new ApplicationUser { UserName = model.Email,
10.	            Email = model.Email, BirthDate = model.BirthDate };
11.	         var result = await UserManager.CreateAsync(user,
12.	             model.Password);
13.	         if (result.Succeeded)
14.	         {
15.	            await SignInManager.SignInAsync(user, isPersistent:false,
16.	               rememberBrowser:false);
17.	 
18.	             / /For more information on how to enable account confirmation
19.	             / /and password reset, please visit
20.	             / /http://go.microsoft.com/fwlink/?LinkID=320771
21.	             / /Send an email with this link
22.	             / /string code = await
23.	             / /UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
24.	             / /var callbackUrl = Url.Action("ConfirmEmail", "Account",
25.	             / /new { userId = user.Id, code = code },
26.	             / /protocol: Request.Url.Scheme);
27.	             / /await UserManager.SendEmailAsync(user.Id,
28.	             / /"Confirm your account",
29.	             / /"Please confirm your account by clicking <a href=\"" +
30.	             / /callbackUrl + "\">here</a>");
31.	 
32.	            return RedirectToAction("Index", "Home");
33.	         }
34.	         AddErrors(result);
35.	      }
36.	 
37.	       / /If we got this far, something failed, redisplay form
38.	      return View(model);
39.	   }

کلاس applicationuser را با افزودن DOB Claim به روز می‌کنیم.

1.	public class ApplicationUser : IdentityUser
2.	   {
3.	      public DateTime BirthDate { get; set; }
4.	      public async Task<ClaimsIdentity>
5.	         GenerateUserIdentityAsync
6.	         (UserManager<ApplicationUser> manager)
7.	      {
8.	          / /Note the authenticationType must match the one defined
9.	          / /in CookieAuthenticationOptions.AuthenticationType
10.	         var userIdentity = await manager.CreateIdentityAsync
11.	            (this, DefaultAuthenticationTypes.ApplicationCookie);
12.	          / /Add custom user claims here
13.	         userIdentity.AddClaim(new Claim(ClaimTypes.DateOfBirth,
14.	            this.BirthDate.ToString()));
15.	 
16.	         return userIdentity;
17.	      }
18.	   }

پس از این کار ما در حقیقت Claim را در مراحل ثبت نام کاربر قرار دادیم.

  1. Verify the Claim

تنها قسمت باقی مانده نوشتن فیلترهایی برای تایید مجوز استفاده از مقادیر بر روی claim ما است. پس از نوشتن این فیلترها باید آنها را بر روی controllers action قرار دهیم.

1.	public class ClaimsAuthorizeAttribute : AuthorizeAttribute
2.	   {
3.	      private string claimType;
4.	      private string claimValue;
5.	      public ClaimsAuthorizeAttribute(string claimType,
6.	         string claimValue)
7.	      {
8.	         this.claimType = claimType;
9.	         this.claimValue = claimValue;
10.	      }
11.	      public override void OnAuthorization(AuthorizationContext
12.	         filterContext)
13.	      {
14.	         var user = filterContext.HttpContext.User as
15.	            ClaimsPrincipal;
16.	         if (user.HasClaim(claimType, claimValue))
17.	         {
18.	            base.OnAuthorization(filterContext);
19.	         }
20.	         else
21.	         {
22.	            base.HandleUnauthorizedRequest(filterContext);
23.	         }
24.	      }
25.	   }

Claim روز تولد در حقیقت نیازمند بررسی‌های بیشتری است. برای این منظور ما vrtification یک claim را فقط برای نشان دادن روش کار آن در Controllers\HomeController.cs قرار می‌دهیم.

1.	   public class HomeController : Controller
2.	   {
3.	      public ActionResult Index()
4.	      {
5.	         return View();
6.	      }
7.	 
8.	      public ActionResult About()
9.	      {
10.	         var user = HttpContext.User as ClaimsPrincipal;
11.	         if (!user.HasClaim(c => c.Type ==
12.	            ClaimTypes.DateOfBirth))
13.	         {
14.	            ViewBag.Message = "Cannot detect the Age -
15.	               Claim is absent. ";
16.	            return View();
17.	         }
18.	 
19.	         int minAge = 16;
20.	         var dateOfBirth = Convert.ToDateTime(user.FindFirst(c =>
21.	            c.Type == ClaimTypes.DateOfBirth).Value);
22.	 
23.	         if (calculateAge(dateOfBirth) >= minAge)
24.	         {
25.	            ViewBag.Message = "You can view this page.";
26.	         }
27.	         else
28.	         {
29.	            ViewBag.Message = "Your cannot view this page -
30.	               your age is bellow permitted one. ";
31.	         }
32.	 
33.	         return View();
34.	      }
35.	 
36.	      private int calculateAge(DateTime dateOfBirth)
37.	      {
38.	         int calculatedAge = DateTime.Today.Year -
39.	            dateOfBirth.Year;
40.	         if (dateOfBirth >
41.	            DateTime.Today.AddYears(-calculatedAge))
42.	         {
43.	            calculatedAge--;
44.	         }
45.	         return calculatedAge;
46.	      }
47.	 
48.	      public ActionResult Contact()
49.	      {
50.	         ViewBag.Message = "Your contact page.";
51.	 
52.	         return View();
53.	      }
54.	   }

می‌بینید که کار ما به چه شکل انجام شد و نتیجه داد. برای اینکه از درستی کدهای نوشته شده و اجرای صحیح آن‌ها مطمئن شویم، ما با تاریخ 04/14/2016 در نرم افزار ثبت نام کردیم و نتیجه‌ای به شکل زیر برای ما نمایش داده شد.

نتیجه نهایی بعد از وارد کردن تاریخ تولد
نتیجه نهایی بعد از وارد کردن تاریخ تولد

آموزش claim در mvc

ما در این مقاله به آموزش claim در mvc پرداختیم و با روش کار claim به شکل کامل آشنا شدیم و دیدیم که چگونه می‌توان از آن استفاده کرد. امروزه استفاده از claim در MVC بسیار رواج پیدا کرده و افراد بسیاری از آن استفاده می‌کنند و یکی از عناصر جدا نشدنی authentication در MVC است.

منابع

https://www.codeguru.com/csharp/.net/net_security/asp.net-mvc-and-claim-based-security.html

https://docs.microsoft.com/en-us/aspnet/core/security/authorization/claims?view=aspnetcore-5.0