پياده سازي امنيت بر اساس Role در ASP.NET MVC
شناسه پست: 1137
بازدید: 2835

چکیده: کلاس 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 ایجاد نمایید:

پروژه asp.net

در نتیجه پروژه MVC با رفرنس های زیر برای ASP.NET Identity ایجاد خواهد شد:

Asp.net identity refrence

در پوشه مدل در پروژه، ما یک کلاس با نام 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 بروید و کاربران را با نقش های مورد نظر ایجاد نمایید:

ثبت نام کاربر در mvc

زمانی که دکمه Register کلیک شد کاربر مورد نظر با یکی از نقش های Manager or Sales Executive ثبت نام خواهد شد.

دو کاربر ایجاد نمایید:

Mahesh1@user.com – این کاربری است با نقش Manager

User1.user@user.com – این کاربری است با نقش Sales Executive

برنامه را stop نمایید و سپس  server explorer را بررسی نمایید. جداول کاربران ونقش ها نمایش داده خواهند شد:

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>

 

برنامه را اجرا نمایید. صفحه زیر نمایش داده خواهد شد:

appbar

روی All Products کلیک نمایید که در نتیجه Index View با تمام محصولات نمایش داده می شود:

نمایش تمام محصولات در mvc

روی لینک Create New کلیک نمایید که در نتیجه صفحه login  نمایش داده خواهد شد. مشضخصات ورود برای کاربر (Mahesh1@user.com) که دسترسی Manager  دارد را وارد نمایید و یک view برای ایجاد محصول نمایش داده خواهد شد. اگر به جای Manager مشخصات  کاربر (user1.user@user.com) با نقش Sales Executive وارد میشد سپس یک صفحه خطا نمایش داده میشد:

فرم login در mvc

با user1.user@use.com لاگین نمایید و از آنجایی که این کاربر دسترسی Sales Executive دارد سپس قادر نیست محصول جدید اضافه نماید و به همین دلیل با صفحه خطای زیر روبه رو خواهد شد:

authorize failed در mvc

شما می توانید برای دانلود سورس کامل اینجا کلیک نمایید.

نتیجه گیری

کلاس IdentityRole  موجود در ASP.NET Identity تعدادی ویژگی های مفید برای ایجاد و مدیریت نقش ها در یک اپلیکیشن در اختیار ما قرار می دهد که ما میتوانیم از آنها برای مدیریت دسترسی کاربران استفاده نماییم.

نویسنده

امید عباسی
من امید عباسی هستم. سالهاست که در زمینه برنامه نویسی با تکنولوژی دات نت فعالیت میکنم و عاشق این هستم که تجربیات و دانش خودم را در این زمینه با دیگران به اشتراک بزارم. خیلی دوست دارم که نظر و انتقاد خودتون رو در مورد این نوشته برای من بنویسید تا بتونم در آینده، مطالب بهتر و ارزشمندتری را برای شما فراهم کنم. در صورت داشتن هرگونه سوال هم در قسمت دیدگاه ها میتونید با بنده در ارتباط باشید