ably ably برای هدایت شدن به سایت جدید اینجا کلیک کنید

آموزش برنامه نویسی

آموزش برنامه نویسی وب، اندروید، ویندوز , اسکیوال و...
Tell: 0912 097 5516
| Email: Hello@EduOnline.ir

آموزش Asp.net Identity MVC

بسم الله الرحمن الرحیم

آموزش Authentication در MVC

آموزش Asp.net Membership

آموزش ASP.NET Identity

آموزش 2 ASP.NET Identity

آموزش 3 ASP.NET Identity


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


Project Setup

یک Empty ASP.NET MVC web application ایجاد کنید.
•    از منوی File  گزینه  New Project و سپس "ASP.NET Web Application" را انتخاب کنید.
•    از پنجره  باز شدهASP.NET  گزینه "Empty" و در قسمت تنظیمات گزینه MVC را انتخاب کنید.

Asp.net Identity

ASP NET Identity


حال یک پروژه ASP.NET MVC application ایجاد کردید.


Install NuGet packages

تمام کتابخانه های ASP.NET Identity از طریق NuGet قابل نصب هست.
ما چون می خواهیم از روش Cookie استفاده کنیم پس باید دو کتابخانه را نصب کنیم.

Microsoft.Owin.Host.SystemWeb

ASP.NET Identity عملا بر روی Owin ایجاد شده است و تمامی ویژگی های ASP.NET Identity می تواند بر روی تمامی frameworkهای Owin مانند: Web API  و  SignalRاستفاده شود. این package درخواست های pipeline را به IIS به وسیله میان افزار یا لایه میانی Owin  را انتقال می دهد.

Install-Package Microsoft.Owin.Host.SystemWeb

Owin را در این بخشی قبلا به صورت مجزا معرفی کرده ام.

 Microsoft.Owin.Security.Cookies

این Package احراز هویت یا authentication را بر اساس cookie فعال می کند.

Install-Package Microsoft.Owin.Security.Cookies

Bootstrapping OWIN

برای initialize کردن کامپوننت OWIN identity ما نیاز به یک کلاس به نام Startup در پروژه خود داریم. در این کلاس متد Configuration یک OWIN به وسیله شیی از IAppBuilder به عنوان پارامتر ایجاد می کند.

این کلاس به صورت اتوماتیک توسط هاست OWIN مقداردهی و initialized می شود.

using Microsoft.Owin;
using Microsoft.Owin.Security.Cookies;
using Owin;

namespace NakedIdentity.Mvc
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = "ApplicationCookie",
                LoginPath = new PathString("/auth/login")
            });
        }
    }
}

UseCookieAuthentication

UseCookieAuthentication در واقع به ASP.NET Identity framework می گوید که از روش cookie  authentication استفاده کند. ما باید دو properties را مقداردهی کنیم.

AuthenticationType

این یک رشته است که کوکی را به وسیله آن کوکی را شناسایی می کند. این پراپرتی زمانی لازم است که شما چندین شی از کوکی برای احراز هویت دارید. بامثالی سعی می کنم مطلب را روشن تر کنم:
هنگامی که ما از روش های احراز هویت خارجی مانند (OAuth/OpenID) با همین کوکی استفاده می کنیم این کوکی بدون اینکه از شما بخواهد تمام اطلاعات اضافی دیگری را که برای احراز هویت کاربر مانند ایمیل، نام کاربری، شمار کاربر در کوکی ثبت کردید برای تامیین کنندگان خارجی ارسال می کند.

منظور از احراز هویت خارجی استفاده از سرویس های شبکه های اجتماعی چون facebook و twitter و یا وب سرویس های دیگری چون google است، حتما سایت هایی را دیده اید که می توانید به وسیله گوگل و.. در آنها لاگین کنید. این سرویس توسط ASP.NET Identity قابل انجام است.
ما باید فقط از یک مقدار ثابت برای پراپرتی در Microsoft.AspNet.Identity استفاده کنیم مثال
DefaultAuthenticationTypes.ApplicationCookie است پس ما باید مقدار پراپرتی خود را نیز برابر "ApplicationCookie" قرار دهیم.

LoginPath

مسیری که user agent (browser) باید پس از بررسی صفحه در صورت عدم دسترسی کاربر و خطای  unauthorized (401) به آن هدایت شود را مشخص می کند.
در اینجا AuthContoller من هست و نام اکشن من نیز LogIn است پس آدرس من می شود

/auth/login


Secure by Default

کلاس زیر را ایجاد کنید

using System.Web.Mvc;

namespace NakedIdentity.Mvc
{
    public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
            filters.Add(new AuthorizeAttribute());
        }
    }
}

حال در متد Application_Start  کلاس global.asax.cs آن را به صورت زیر ثبت کنید

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
}


Create a "protected" resource

ما منابعی داریم که باید پس از لاگین کردن کاربر نمایش داده شوند، بنابراین یک کنترلر به صورت زیر ایجاد می کنیم:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }
}

متناسب با کنترلرمان یک view برای آن ایجاد می کنیم

@{
    ViewBag.Title = "Home";
}

<h2>Home</h2>

ساخت  Auth controller

حال ما باید یک Auth controller و یک اکشن در جایی که کاربر نیاز است redirect شود را در زمانی که انها می خواهند لاگین کنند ایجاد کنیم.

[AllowAnonymous]
public class AuthController : Controller
{
    public ActionResult LogIn()
    {
        return View();
    }
}


خاصیت AllowAnonymous به این معنا است که تمامی کاربران اجازه دسترسی به این اکشن را بدون احراز هویت دارند.
حال view کنترلر را نیز ایجاد می کنیم.

@{
    ViewBag.Title = "Log In";
}

<h2>Log In</h2>


برنامه را اجرا کنید

ما کنترلر Home با viewایی با نام index ایجاد کردیم و چون تنظیمات route پیش فرض ما در پروژه (App_Start/RouteConfig.cs) کنترلر پیش فرض را Home و همچنین view پیش فرض را index معرفی می کند وقتی ما ادرس را فقط با /)) به سرور مجازی خود ارسال می کنیم به کنترلر home و view، index هدایت می شویم اما چون HomeController یک منبع محافظت شده است پس باید قبل از دسترسی به آن لاگین کنیم به همین دلیل به آدرس auth/login هدایت می شویم

آدرس در مرورگر شما شبیه به این آدرس است:

http://localhost:1464/auth/login?ReturnUrl=%2F


Logging in

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


public class LogInModel
{
    [Required]
    [DataType(DataType.EmailAddress)]
    public string Email { get; set; }

    [Required]
    [DataType(DataType.Password)]
    public string Password { get; set; }

    [HiddenInput]
    public string ReturnUrl { get; set; }
}

ما از چند data annotation برای تعریف پراپرتی ها و همچنین چند MVC's HTML helpers برای ساخت فرم لاگین استفاده کرده ایم.
در بخش های قبلی data annotation ها را توضیح داده ام می توانید آن ها را بررسی کنید که بسیار مفید خواهد بود.

حالا ما باید AuthController را تغییر دهیم. در ابتدا ما یک اکشن از نوع GET خواهیم داشت که صفحه لاگین را نمایش خواهد داد.

[HttpGet]
public ActionResult LogIn(string returnUrl)
{
    var model = new LogInModel
    {
        ReturnUrl = returnUrl
    };

    return View(model);
}


درست مانند یک ماژول Forms Authentication، url منابع محافظت شده ای که کاربر اقدام به دسترسی به آنها کرده است یک آدرس با نام returnUrl به صورت querystring ارسال می کند. هنگامی که فرم لاگین را برای کاربر ارسال می کنیم اطلاعات آدرس صفحه ای که کاربر برای ما ارسال می کند را درون LogInModel به وسیله یک hidden input کنترل ذخیره می کنیم.
این کار باعث می شود تا پس از اینکه در صفحه لاگین، احراز هویت کاربر انجام شد و به نوع کاربر لاگین کرد، ما بدانیم کاربر قبل از این مرحله چه صفحه ای را می خواسته است باز کند و او را به همان صفحه بفرستیم.

حال اکشن بررسی اطلاعات کاربر برای ورود را می نویسیم، اکشن POST /auth/login وظیه بررسی و اعتبارسنجی را بر عهده دارد.


[HttpPost]
public ActionResult LogIn(LogInModel model)
{
    if (!ModelState.IsValid)
    {
        return View();
    }

    // Don't do this in production!
    if (model.Email == "admin@admin.com" && model.Password == "password")
    {
        var identity = new ClaimsIdentity(new[] {
                new Claim(ClaimTypes.Name, "Esmaeil"),
                new Claim(ClaimTypes.Email, "a@b.com"),
                new Claim(ClaimTypes.Country, "Iran")
            },    
            "ApplicationCookie");

        var ctx = Request.GetOwinContext();
        var authManager = ctx.Authentication;

        authManager.SignIn(identity);

        return Redirect(GetRedirectUrl(model.ReturnUrl));
    }

    // user authN failed
    ModelState.AddModelError("", "Invalid email or password");
    return View();
}

private string GetRedirectUrl(string returnUrl)
{
    if (string.IsNullOrEmpty(returnUrl) || !Url.IsLocalUrl(returnUrl))
    {
        return Url.Action("index", "home");
    }

    return returnUrl;
}



در حال حاضر ما به صورت خیلی ساده منظق احراز هویت را پیاده سازی کرده ایم، ما ایمیل و کلمه عبوری را به صورت hardcode در نظر گرفته ایم و آن را با ایمیل و کلمه عبور کاربر بررسی می کنیم، در آینده ما باید این اطلاعات را از دیتابیس بخوانیم.
این کد وقتی جذاب می شود که ما کاربر را تایید می کنیم.
1.    در ابتدا ما یک شی از کلاس ClaimsIdentity شامل اطلاعات (Claims) در مورد کاربر جاری ایجاد می کنیم. جذابیت خاص معماری جدید Claims مبتنی بر
این به این معنی است که شما می توانید اطلاعاتی را که بسیار به آن مراجعه می کنید به claims اضافه کنید ، تا  مجبور نشوید برای هر کاری مجددا به دیتابس مراجعه کنید و سرعت برنامه خود را افزایش دهید.
این شبیه به چیزی است که ما مجبور بودیم در Identity بر اساس Session Authentication Module (SAM) ایجاد کنیم.(البته اگر می خواستیم سرعت کار ما زیاد شود.).همچنین ما می توانیم authentication type را مشخص کنیم، اما یادتان باشد این مقدار باید با مقدار مشخص شده در کلاس Startup مشابه باشد.
2.    ما یک شی IAuthenticationManager را از OWIN context جاری بدست می آوریم. این به صورت اتوماتیک برای شما در زمان startup ثبت می شد.
3.    سپس ما IAuthenticationManager.SignIn را برای انتقال claims identity فراخوانی می کنیم. این authentication cookie را برای ما در کلاینت ثبت می کند (از نظر من اوج لذت)
4.    در نهایت ما user agent را به صفحه ای که می خواسته به آن دسترسی پیدا کند redirect می کنیم.
ما همچنین، برای اطمینان حاصل کردن از اینکه return URL یک آدرس local در برنامه است آن را چک می کنیم تا دچار حملاتOpen Redirection  نشویم.

در نهایت ما فقط نیاز داریم تا LogIn.cshtml را به صورت زیر تغییر دهیم

@model NakedIdentity.Mvc.ViewModels.LogInModel
@{
  ViewBag.Title = "Log In";
}

<h2>Log In</h2>

@Html.ValidationSummary(true)

@using (Html.BeginForm())
{
  @Html.EditorForModel()
  <p>
    <button type="submit">Log In</button>
  </p>
}


اجرا برنامه

اگر شما از اطلاعات معتبر استفاده کنید شما می توانید لاگین کنید و به صفحه home انتقال پیدا کنید
برای لاگین کردن از (admin@admin.com/password) استفاده کنید.

چطور بدانیم که شما لاگین کرده اید؟
کد زیر را به Home view اضافه کنید

<p>
  Hello @User.Identity.Name
</p>


صفحه راRefresh  کنید تا اطلاعات زیر را ببینید:

Hello Esmaeil

Logging Out

کد زیر را اضافه کنید

public ActionResult LogOut()
{
    var ctx = Request.GetOwinContext();
    var authManager = ctx.Authentication;

    authManager.SignOut("ApplicationCookie");
    return RedirectToAction("index", "home");
}


دوباره ما از OWIN context یک نمونه IAuthenticationManager را بدست می آوریم اما این بار SignOut را به authentication type انتقال می دهیم.
پس manager عملا می داند چه کوکی را باید حذف کند.
ما لینک خروج را نیز به home page اضافه می کنیم.

<p>
  <a href="@Url.Action("logout", "auth")">Log Out</a>
</p>


Accessing custom claim data

در حالیکه claims بر اساس principals/identities در ASP.NET مورد استفاده قرار می گیرد، کاربر جاری هنوز هم به وسیله IPrincipal/IIdentity نمایش داده می شود،این بدین معنا است که ما واقعا می توانیم دریافت کنیم از User property در کنترلرها و viewهایی که در Name claim هستند.
برای دسترسی به سایر claims دیگر، ما می توانیم Cast کنیم current user identity با ClaimIdentity.
Index اکشن را در HomeController به صورت زیر بروز رسانی کنید:

public ActionResult Index()
{
    var claimsIdentity = User.Identity as ClaimsIdentity;
    ViewBag.Country = claimsIdentity.FindFirst(ClaimTypes.Country).Value;

    return View();
}



حال Home/Index.cshtml  را به صورت زیر تغییر دهید

<p>
  Hello @User.Identity.Name. How's the weather in @ViewBag.Country?
</p>

شما باید خروجی زیر را دریافت کنید

Hello Esmaeil. How's the weather in Iran

The smarter way

هربار که شما می خواهید دسترسی به user claims پیدا کنید باید این کار را انجام دهید، اگر شما مجبور باشید به صورت strongly typed برای user claims خود دسترسی داشته باشید، روش خوبی نیست.

ما این کار را با ایجاد کلاس Principal که ClaimsPrincipal جاری را به همراه پراپرتی strongly typed  در claims تکمیل می کند انجام می دهیم

public class AppUser : ClaimsPrincipal
{
    public AppUser(ClaimsPrincipal principal)
        : base(principal)
    {
    }

    public string Name
    {
        get
        {
            return this.FindFirst(ClaimTypes.Name).Value;
        }
    }

    public string Country
    {
        get
        {
            return this.FindFirst(ClaimTypes.Country).Value;
        }
    }
}

حال ما باید base controller را که دسترسی به AppUser  فراهم می کند را نیز اضافه کنیم

public abstract class AppController : Controller
{       
    public AppUser CurrentUser
    {
        get
        {
            return new AppUser(this.User as ClaimsPrincipal);
        }
    }
}

در نهایت ما HomeController را به صورت زیر تغییر می دهیم.

public class HomeController : AppController
{
    public ActionResult Index()
    {
        ViewBag.Country = CurrentUser.Country;
        return View();
    }
}


خیلی بهتر شد.
اما باز همی می توان آن را بهتر نمود.چرا نیاز است  ما اطلاعات را به ViewBag اضافه کنیم در صورتی که ما از درون view ها قبلا دسترسی به کاربر جاری داشتیم.

خوب بیاید یک custom base view page را برای Razor views خودمان که دسترسی بهAppUser  را فراهم می کند ایجاد کنیم.

public abstract class AppViewPage<TModel> : WebViewPage<TModel>
{
    protected AppUser CurrentUser
    {
        get
        {
            return new AppUser(this.User as ClaimsPrincipal);
        }
    }
}

public abstract class AppViewPage : AppViewPage<dynamic>
{
}

فایل views/web.config را باز کنید pageBaseType را تنظیم کنید.

<system.web.webPages.razor>
  <pages pageBaseType="NakedIdentity.Mvc.AppViewPage">

پروژه را Rebuild کنید و Index.cshtml را تغییر دهید:

<p>
  Hello @CurrentUser.Name. How's the weather in @CurrentUser.Country?
</p>


HomeController الان به سادگی می تواند یک view را برگرداند

public ActionResult Index()
{
    return View();
}


انشاالله که متوجه شده باشید یکcookie based authentication  در  ASP.NET MVC  با استفاده از ASP.NET Identity  چطور انجام می شود.

در مطلب بعدی ارتباطات ASP.NET identity و دیتابیس را بررسی خواهیم کرد

نظرات (۹)

faghat khastam begam karetooon kheili alieeeee merccc mamnooon
mishe raje be async va await ham tozih maghale benevisin
bazam mamnoon
پاسخ:
با عرض سلام خدمت شما و ممنون از لطفتان
حتما، سعی خواهم کرد مطلبی در این خصوص آماده کنم
یاعلی
سلام
خواستم بگم دمتون گرم
من تازه کارم و مطالبتون خیلی کمک میکنه
حتما به همه دوستام معرفیتون میکنم
لازم میدونستم تشکر کنم
ممنون از زحماتتون
پاسخ:
با عرض سلام
از لطف شما بسیار متشکرم
یاعلی
من هنوز مطلب رو کامل نخوندم ولی تا همین جا از اینکه این مطلب رو در اختیار ما قرار دادید ازتون تشکر میکنم 
پاسخ:
با عرض سلام خدت شما دوست عزیز
انشالله که در پایان با خواندن این مطالب بتوانید به خوبی از آنها استفاده کنید
موفق باشید
من یه مشکلی دارم. توی یه مرورگر با دو تا سامانه متفاوت لاگین هستند. یکی با SimpleMembership و دیگری با همین ASP.NET Identity به همین شیوه مطرح شده در این مطلب. ولی هنگام لاگ آف از سامانه دوم، ظاهرا لاگ آف نمیشه. بررسی کردم، متوجه شدم ظاهرا توی Idenity.Name سامانه دوم، Name  مربوط به سامانه اول بود و Authorize محسوب میشد! عجیب بود. دلیلش رو کسی میدونه؟
پاسخ:
با عرض سلام

در تمامی سیستم های مدیریت سطح دسترسی بر دو اساس احراز هویت ها کار خواهند کرد یکی بر اساس session و دیگری بر اساس cookie طبیعتا Id ایی که به ازاری هر کاربر ساخته می شود مرتبط با آی پی و اطلاعات Http_header است.
در اینجا چون شما از یک Root استفاده می کنید طبیعتا اطلاعات ثبت شده در سیستم اول با اطلاعات ثبت شده در سیستم دوم مطابقت داده می شود و به همین دلیل وقتی با یک سیستم لاگین می کنید در سیستم دوم نیز مورد تایید قرار می گیرید.
موفق باشید
یاعلی
با سلام
می خواستم بدونم که آیا امکان طراحی یک احراز هویت خارجی سفارشی وجود دارد مثلا   Authentication از طریق سرویسی که من نوشتم انجام شود.

با تشکر



پاسخ:
با عرض سلام

بله، شما می توانید متدهای مربوط به احراز هویت و حتی روش مربوط به احراز هویت (قبل از اجرا شدن هر Action) را نیز شخصی سازی کنید.

باتشکر
سلام
فکر کنم منظورم رو به خوبی بیان نکردم من می خواستم سرویسی مانند مثلا Facebook  راه اندازی کنم که از این به بعد جهت احراز هویت از سرویس من استفاده بشه اگه منبعی برای این کار معرفی کنید ممنون میشم .
پاسخ:
با سلام

همانطور که خودتان اشاره کرده اید باید "سرویسی" را برای این کار طراحی کنید و سپس بر اساس ورودی های این سرویس خروجی مناسبی را برگردانید و بر اساس آن به کاربر اجازه لاگین کردن بدهید و همچنین میتوانید بعد از مشخص شدن هویت کاربر اطلاعات فردی وی را نمایش دهید.
بهترین و ساده ترین روش برای شروع و ایجاد یک مثال طراحی یک وب سرویس با استفاده از web api می باشد که این وب سرویس شما نام کاربری و کلمه عبور hash شده را دریافت و تعیین می کند که کاریری با این مشخصات وجود دارد و یا خیر.
در همین وب سایت قبلا دوره آموزشی web api را قرار داده ایم که می توانید از آن کمک بگیرید.

موفق باشید
  • فرشید علی اکبری
  • سلام
    آموزش DI در MVC به کمک StructureMap در سایتهای مختلف پیدا میشه، ولی با توجه به تفهیم بهتر و قلم شیوا و ساده ای که شما یرای تدریس در دست دارید این مبحث هم در این سایت اضافه شود بسیار عالی خواهد بود.

    با تشکر از زحمات شما عزیزان.
    پاسخ:
    با عرض سلام

    چشم حتما سعی خواهیم کرد به این موضوع نیز بپردازیم.

    باتشکر
    سلام
    ای کاش سورس کد آموزش رو هم قرار می دادید
    پاسخ:
    با عرض سلام

    در اکثر مثالهایی که به صورت پروژه ای بررسی شده اند، کدها در آخر دوره قرار داده شده اند.

    باتشکر
    سلام 
    آیا این آموزش identity 2 هست؟
    پاسخ:
    با عرض سلام
    تمام مفاهیم مشترک می باشد و اگر شما در پروژه تان از asp identity 1 استفاده کرده باشید به سادگی می تواند آن را به  asp identity 2 ارتقاء دهید.
    ارسال نظر آزاد است، اما اگر قبلا در بیان ثبت نام کرده اید می توانید ابتدا وارد شوید.
    شما میتوانید از این تگهای html استفاده کنید:
    <b> یا <strong>، <em> یا <i>، <u>، <strike> یا <s>، <sup>، <sub>، <blockquote>، <code>، <pre>، <hr>، <br>، <p>، <a href="" title="">، <span style="">، <div align="">
    تجدید کد امنیتی
    up
    ما را در گوگل محبوب کنید