چکیده: کلاس IdentityRole در ASP.NET، تعدادی ویژگی های مفید برای ایجاد و مدیریت Role ها در یک برنامه در اختیار ما قرار میدهد.
یک چالش بزرگ در هر برنامه تحت وب، پیاده سازی امنیت در آن است. ما در توسعه اپلیکیشن های وب به صورت سنتی با ASP.NET (از ورژن 2 به بعد) از Membership provider و Role provider استفاده میکردیم. این provider ها به ما اجازه میداد تا نقش ها و کاربران را تعریف نماییم و نقش ها را به کاربران اختصاص دهیم که این کار کمک میکرد تا بتوانیم احراز هویت در برنامه هایمان را مدیریت نماییم. اما با افزایش شبکه های اجتماعی و سیستمهای ارائه دهنده احراز هویت جهانی، نیاز به یک سیستم عضویت به روز شده حائز اهمیت بود. ASP.NET Identity یک سیستم عضویت جدید برای ایجاد برنامه های تحت وب با ASP.NET،برنامه های موبایل، فروشگاهی با استفاده از سیستمهای ارائه دهنده احراز هویت توسط شبکه های اجتماعی جهت احراز هویت و مجوز می باشد. بنابراین در حال حاضر ما میتوانیم قبل از اینکه کاربر شروع به استفاده از برنامه ما نماید از Windows Live (برای مثال Hotmail ) و Gmail، Facebook و Twitter برای احراز هویت استفاده نماییم. برای علاقه بیشتر، شما می توانید مقاله پیاده سازی امنیت با ASP.NET Identity 2.0 در اپلیکیشن های ASP.NET MVC را مطالعه نمایید.
من می خواهم توجه شما را به این نکته جلب کنم که ما نمی توانیم از Windows Windows ، Gmail ، Facebook یا Twitter برای اهداف احراز هویت (authentication) برای برنامه های وب در سطح Internal مانند دسترسی کاربران به ایجاد محصولات یا مدیریت سایر کاربران استفاده نماییم. بنابراین برای اپلیکیشن های داخلی، ما باید کاربران و نقش های مورد نظر را ایجاد نماییم. خوشبختانه MVC 5، رفرنس های مورد نیاز برای ASP.NET Identity را در اختیار ما قرار می دهد. این رفرنس ها این امکان را د راختیار ما قرار می دهند تا از external login ها همچون gmail، facebook و غیره استفاده نماییم و همچنین این اجازه را به ما می دهد تا بتوانیم نقش ها و کاربران مورد نظر را برای اپلیکیشن های internal ایجاد نماییم. من در این مثال از Twitter Bootstrap برای طراحی UI استفاده می کنم.
ایجاد اپلیکیشن ASP.NET MVC، پیکربندی و ایجاد نقش ها و کاربران
مرحله 1: ویژوال استودیو را باز نمایید و یک MVC application با نام A11_RBS از نوع MVC Template ایجاد نمایید:
در نتیجه پروژه MVC با رفرنس های زیر برای ASP.NET Identity ایجاد خواهد شد:
در پوشه مدل در پروژه، ما یک کلاس با نام IdentityModel.cs داریم. این فایل شامل کلاس ApplicationDbContext برای اتصال به دیتابیس می باشد. دیتابیسی که کاربران و نقش ها در آن ایجاد و نگه داری خواهند شد. کلاس AccountViewModels کلاسی برای ورود، ثبت نام و غیره برای کاربران می باشد. به کلاس RegisterViewModel درون این فایل بروید و فیلد زیر را درون آن قرار دهید:
public string Name { get ; set ; } |
این فیلد برای اختصاص دادن نقش به کاربر جدیدی که در اپلیکیشن ثبت نام کرده است به کار می رود.
مرحله 2: حال باید یک View برای ثبت نقش در برنامه ایجاد نماییم. برای این منظور، در پوشه Controllers یک Empty MVC controller به نام RoleController ایجاد نمایید. در این کنترلر، کدهای زیر را قرار دهید:
using System; using System.Linq; using System.Web.Mvc; using A11_RBS.Models; using Microsoft.AspNet.Identity.EntityFramework; namespace A11_RBS.Controllers { public class RoleController : Controller { ApplicationDbContext context; public RoleController() { context = new ApplicationDbContext(); } /// <summary> /// Get All Roles /// </summary> /// <returns></returns> public ActionResult Index() { var Roles = context.Roles.ToList(); return View(Roles); } /// <summary> /// Create a New role /// </summary> /// <returns></returns> public ActionResult Create() { var Role = new IdentityRole(); return View(Role); } /// <summary> /// Create a New Role /// </summary> /// <param name="Role"></param> /// <returns></returns> [HttpPost] public ActionResult Create(IdentityRole Role) { context.Roles.Add(Role); context.SaveChanges(); return RedirectToAction( "Index" ); } } } |
ایجاد نقش با استفاده از کلاس IdentityRole انجام می شود. این کلاس شامل خصوصیاتی همچون Id، Name و غیره برا ثبت نقش در اپلیکیشن می باشد. با اسفاده از اکشن متد Create و Index در کلاس RoleController ، ویوهای آنها را Scaffold نمایید.
Index.cshtml
@model IEnumerable<Microsoft.AspNet.Identity.EntityFramework.IdentityRole> @{ ViewBag.Title = "Index" ; } <h2>Available Roles For Application</h2> @Html.ActionLink( "Create Role" , "Create" , "Role" ) <style type= "text/css" > #tbrole,.c { border: double ; } </style> <table id= "tbrole" > <tr> <td class = "c" > Role Name </td> </tr> @ foreach (var item in Model) { <tr> <td class = "c" > @item.Name </td> </tr> } </table> |
Create.cshtml
@model Microsoft.AspNet.Identity.EntityFramework.IdentityRole @{ ViewBag.Title = "Create" ; } <h2>Create</h2> <style type= "text/css" > #tbrole, .c { border: double ; } </style> @ using (Html.BeginForm()) { <table id= "tbrole" > <tr> <td class = "c" >Enter Role Name To be Created:</td> <td class = "c" > @Html.EditorFor(m => m.Name) </td> </tr> </table> <input type= "submit" value= "Create Role" /> } |
مرحله 3: AccountController.cs را باز نمایید و سپس یک نمونه از ApplicationDbContext را در سازنده AccountController ایجاد نمایید:
ApplicationDbContext context; public AccountController() { context = new ApplicationDbContext(); } |
کد زیر را در اکشن متد Register() قرار دهید:
[AllowAnonymous] public ActionResult Register() { ViewBag.Name = new SelectList(context.Roles.ToList(), "Name" , "Name" ); return View(); } |
این کد اطلاعات نقش ها را در Register View بارگزاری می نماید. بنابراین زمانی که یک کاربر جدید در اپلیکیشن ثبت نام می شود، نقش مورد نظر به کاربر تخصیص داده می شود. Register.cshtml view موجود در پوشه Account در پوشه Views را باز نمایید و سپس Html Helper زیر را در بالای دکمه Submit در آن قرار دهید:
<!--Select the Role Type for the User--> < div class = "form-group" > @Html.Label("Select Your User Type", new { @class = "col-md-2 control-label" }) < div class = "col-md-10" > @Html.DropDownList("Name") </ div > </ div > <!--Ends Here--> |
برای تکمیل عملیات تخصیص نقش به کاربر، اکشن متد Register() از نوع HttpPost در AccountController را به صورت زیر تغییر دهید:
[HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> Register(RegisterViewModel model) { if (ModelState.IsValid) { var user = new ApplicationUser { UserName = model.Email, Email = model.Email }; var result = await UserManager.CreateAsync(user, model.Password); if (result.Succeeded) { //Assign Role to user Here await this .UserManager.AddToRoleAsync(user.Id, model.Name); //Ends Here await SignInManager.SignInAsync(user, isPersistent: false , rememberBrowser: false ); return RedirectToAction( "Index" , "Home" ); } AddErrors(result); } // If we got this far, something failed, redisplay form return View(model); } |
مرحله 4: در _Layout.cshtml view موجود در پوشه Shared از پوشه Views، قطعه کد زیر را برای نمایش لینک برای Role درون یک تگ <div> با کلاس navbar-collapse collapse قرار دهید:
< li >@Html.ActionLink("Role", "Index", "Role")</ li > |
مرحله 5: برنامه را اجرا نمایید. سپس به Create View برای RoleController بروید و نقش های Manager و Sales Executive را ایجاد نمایید. سپس به اکشن متد Register در Account Controller بروید و کاربران را با نقش های مورد نظر ایجاد نمایید:
زمانی که دکمه Register کلیک شد کاربر مورد نظر با یکی از نقش های Manager or Sales Executive ثبت نام خواهد شد.
دو کاربر ایجاد نمایید:
Mahesh1@user.com – این کاربری است با نقش Manager
User1.user@user.com – این کاربری است با نقش Sales Executive
برنامه را stop نمایید و سپس server explorer را بررسی نمایید. جداول کاربران ونقش ها نمایش داده خواهند شد:
استفاده از احراز هویت برای کنترل کردن دسترسی ها به اکشن متدهای موجود در controller
زمانی که نقش ها و کاربران ایجاد و پیکربندی شدند سپس باید آنها را مدیریت و سطح دسترسی برای آنها را تعریف نماییم. ما برای این کار یک اپلیکیشن ساده برای فروش محصولات یک سوپرمارکت پیاده سازی می نماییم. در این مثالف محصول توسط نقش Manager به سیستم اضافه و توسط نقش Sales Executive می تواند فروخته شود.
مرحله 1: در پوشه App_Data، یک دیتابیس Sql Server جدید با نام SuperMarket اضافه نمایید. در این دیتابیس، جدول زیر را اضافه نمایید:
مرحله 2: در پوشه Models، یک ADO.NET Entity Data Model جدیداضافه نمایید. در پنجره wizard ، دیتابیس SuperMarket.mdf و جدول ProductMaster را انتخاب نمایید. ویزارد را تولید مپ کردن جدول کامل نمایید. پروژه را Build نمایید.
مرحله 3: در پوشه Controllers، یک empty MVC Controller جدید با نام ProductController اضافه نمایید. اکشن متدهای زیر را درون آن قرار دهید:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using A11_RBS.Models; namespace A11_RBS.Controllers { public class ProductController : Controller { SuperMarketEntities ctx; public ProductController() { ctx = new SuperMarketEntities(); } // GET: Product public ActionResult Index() { var Products = ctx.ProductMasters.ToList(); return View(Products); } public ActionResult Create() { var Product = new ProductMaster(); return View(Product); } [HttpPost] public ActionResult Create(ProductMaster p) { ctx.ProductMasters.Add(p); ctx.SaveChanges(); return RedirectToAction( "Index" ); } public ActionResult SaleProduct() { ViewBag.Message = "This View is designed for the Sales Executive to Sale Product." ; return View(); } } } |
این کنترلر شامل اکشن متد Index, Create و SaleProduct می باشد. View ها را از این اکشن متذ=دها Scaffold نمایید.
مرحله 4: از آنجایی که ما قصد داریم اکشن Create را به نقش Manager و SaleProduct را به نقش Sales Executive پیکربندی نماییم باید [Authorize (Role=”<Role Name>”)] را بر روی این متدها اعمال نماییم. اما اگر کاربر به اکشن مورد نظر مجوز دسترسی ندارد سپس باید او را به یک صفحه error هدایت نماییم. برای این منظور ما باید یک Action filter سفارشی برای احراز هویت و Error View به پروژه اضافه نماییم.
مرحله 5: در پوشه Views، ما یک زیرپوشه به نام Shared داریم. در این پوشه یک View خالی به نام AuthorizeFailed.cshtml به صورت زیر ایجاد نمایید:
@{ ViewBag.Title = "AuthorizeFailed" ; } <h2>Authorize Failed</h2> @ViewData[ "Message" ] |
مرحله 6: در پروژه یک پوشه جدید با نام CustomFilters اضافه نمایید و یک فایل کلاس با منطق Login به صورت زیر در آن اضافه نمایید:
using System.Web.Mvc; namespace A11_RBS.CustomFilters { public class AuthLogAttribute : AuthorizeAttribute { public AuthLogAttribute() { View = "AuthorizeFailed" ; } public string View { get ; set ; } /// <summary> /// Check for Authorization /// </summary> /// <param name="filterContext"></param> public override void OnAuthorization(AuthorizationContext filterContext) { base .OnAuthorization(filterContext); IsUserAuthorized(filterContext); } /// <summary> /// Method to check if the user is Authorized or not /// if yes continue to perform the action else redirect to error page /// </summary> /// <param name="filterContext"></param> private void IsUserAuthorized(AuthorizationContext filterContext) { // If the Result returns null then the user is Authorized if (filterContext.Result == null ) return ; //If the user is Un-Authorized then Navigate to Auth Failed View if (filterContext.HttpContext.User.Identity.IsAuthenticated) { // var result = new ViewResult { ViewName = View }; var vr = new ViewResult(); vr.ViewName = View; ViewDataDictionary dict = new ViewDataDictionary(); dict.Add( "Message" , "Sorry you are not Authorized to Perform this Action" ); vr.ViewData = dict; var result = vr; filterContext.Result = result; } } } } |
فیلتر سفارشی بالا از کلاس AuthorizeAttribute مشتق شده است و متد OnAuthorization() را override می کند. متد IsUserAuthorized() helper احراز هویت را با کلاس AuthorizationContext بررسی می نماید. اگر خاصیت Result مقدار null برگرداند سپس Authorization مورد قبول می باشد و کاربر می تواند عملیات را ادامه دهد. در غیر اینصورت اگر کاربر authenticate شده است اما مجوزه دسترسی ندارد سپس یک صفحه خطا برگردانده خواهد شد.
مرحله 7: ProductController را باز نمایید و ویژگی AuthLog را روی اکشن متدهای Create و SaleProduct قرار دهید:
[AuthLog(Roles = "Manager" )] public ActionResult Create() { var Product = new ProductMaster(); return View(Product); } [AuthLog(Roles = "Sales Executive" )] public ActionResult SaleProduct() { ViewBag.Message = "This View is designed for the Sales Executive to Sale Product." ; return View(); } |
متد create برای تمام کاربرانی که نقش Manager را دارند مورد دسترسی قرار میگیرد در حالی که SaleProduct برای کاربران با نقش Sales Executive می باشد.
مرحله 8: _Layout.cshtml را از پوشه Views/Shared باز نمایید
و لینکها را برای All Products , New Product و Sale Product درون یک تگ <div> با کلاس navbar-collapse collapse به صورت زیر اضافه نمایید:
< li >@Html.ActionLink("All Products", "Index", "Product")</ li > < li >@Html.ActionLink("New Product", "Create", "Product")</ li > < li >@Html.ActionLink("Sale Product", "SaleProduct", "Product")</ li > |
برنامه را اجرا نمایید. صفحه زیر نمایش داده خواهد شد:
روی All Products کلیک نمایید که در نتیجه Index View با تمام محصولات نمایش داده می شود:
روی لینک Create New کلیک نمایید که در نتیجه صفحه login نمایش داده خواهد شد. مشضخصات ورود برای کاربر (Mahesh1@user.com) که دسترسی Manager دارد را وارد نمایید و یک view برای ایجاد محصول نمایش داده خواهد شد. اگر به جای Manager مشخصات کاربر (user1.user@user.com) با نقش Sales Executive وارد میشد سپس یک صفحه خطا نمایش داده میشد:
با user1.user@use.com لاگین نمایید و از آنجایی که این کاربر دسترسی Sales Executive دارد سپس قادر نیست محصول جدید اضافه نماید و به همین دلیل با صفحه خطای زیر روبه رو خواهد شد:
شما می توانید برای دانلود سورس کامل اینجا کلیک نمایید.
نتیجه گیری
کلاس IdentityRole موجود در ASP.NET Identity تعدادی ویژگی های مفید برای ایجاد و مدیریت نقش ها در یک اپلیکیشن در اختیار ما قرار می دهد که ما میتوانیم از آنها برای مدیریت دسترسی کاربران استفاده نماییم.