آموزش Asp.net Identity
بسم الله الرحمن الرحیم
با توجه به درخواست بسیاری از دوستان پس از نوشتن مقاله معرفی ASP.NET Identity، در خصوص نوشتن یک پروژه برای استفاده از Identity ASP.NET به صورت عملی بنده این مقاله را برای شما آماده کردم. انشالله مفید واقع شود.
آموزش Authentication در MVC
آموزش 3 ASP.NET Identity
در آموزش قبلی شما با فرایند کار ASP.NET Identity آشنا شدید در این مقاله شما نحوه خواندن و بررسی اطلاعات کاربر را با استفاده از SQL Server آموزش خواهید دید.
Storing user information in a database
برای ذخیره اطلاعات در دیتابیس به وسیله ASP.NET Identity ما باید Package زیر را نصب کنیم:
Install-Package Microsoft.AspNet.Identity.EntityFramework
این Package برای ارتباط ما با SQL Server است که به وسیله آن می توانیم اطلاعات خود را دردیتابیس ذخیره کنیم و سپس اطلاعات خود را نیز از دیتابیس بخوانیم.
ایجاد کلاس برای نمایش اطلاعات کاربر
ASP.NET Identity به سادگی به شما اجازه می دهد که اطلاعات اضافی را برای کاربر خود ذخیره کنید. شما برای این کار باید از کلاس IdentityUser استفاده کنید و سپس Property های مورد نیاز خود را برای ثبت اطلاعات بیشتر برای هر کاربر تعریف کنید.
در این مثال ما علاوه بر اطلاعات کاربری فیلد country را نیاز داریم به همین دلیل این فیلد را به صورت زیر اضافه می کنیم:
public class AppUser : IdentityUser
{
public string Country { get; set; }
}
ایجاد DbContext
در حالیکه شما می توانید از کلاس داخلی Identity با نام IdentityDbContext<TUser> برای کار با دیتابیس استفاده کنید.
ASP.NET Identity پیشنهاد می کند که DbContext خود را در هر پروژه ایجاد کنید، این کار به شما اجازه می دهد تا فرایندهای پروژه خود را راحت تر مدیریت کنید شبیه session-per-request و database migrations.
using Microsoft.AspNet.Identity.EntityFramework;
namespace NakedIdentity.Mvc
{
public class AppDbContext : IdentityDbContext<AppUser>
{
public AppDbContext()
: base("DefaultConnection")
{
}
}
}
به صورت پیش فرض Entity Framework نام دیتابیس شما را DefaultConnection قرار می دهد و آن را در مسیر App_Data قرار می دهد. اگر شما می خواهید این اطلاعات را تغییر دهید باید مشابه زیر در فایل Web.Config اطلاعات خود را قرار دهید.
<connectionStrings>
<add name="DefaultConnection"
connectionString="Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\NakedIdentity-Mvc.mdf;Initial Catalog=NakedIdentity-Mvc;Integrated Security=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
شما همچنین باید مطمئن شوید که پوشه App_Data را ایجاد کرده اید در غیر این صورت EF یک خطا throw خواهد کرد.
Configuring UserManager
کلاس UserManagerدر ASP.NET Identity برای مدیریت کاربران مانند ثبت نام کاربر جدید، احراز هویت و لود کردن اطلاعات کاربر مورد استفاده قرار می گیرد. این کلاس با نحوه ذخیره سازی اطلاعات ارتباطی ندارد. برای ذخیره سازی این کلاس به کلاس UserStore که در Entity Framework مدیریت می شود وابسته است.
همچنین پیاده سازی برای Azure Table Storage، RavenDB and MongoDB در کلاس UserStore در دسترس است.
در بخش زیر من از Factory Pattern به صورتی که یک شی جدید از UserManager به ازای هر درخواست ایجاد کنم، استفاده کرده ام (شما می توانید همین کار را با یک ابزار تزریق وابستگی (Dependency Injection) به انتخاب خود انجام دهید).
public class Startup
{
public static Func<UserManager<AppUser>> UserManagerFactory { get; private set; }
public void Configuration(IAppBuilder app)
{
// this is the same as before
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/auth/login")
});
// configure the user manager
UserManagerFactory = () =>
{
var usermanager = new UserManager<AppUser>(
new UserStore<AppUser>(new AppDbContext()));
// allow alphanumeric characters in username
usermanager.UserValidator = new UserValidator<AppUser>(usermanager)
{
AllowOnlyAlphanumericUserNames = false
};
return usermanager;
};
}
}
احراز هویت به وسیله cookie را در مقاله قبلی آموزش دید و نحوه پیکربندی آن را مشاهده کردید.
کلاس UserManager به صورت generic است و یک type از user (در برنامه ما AppUser) ایجاد می کند. همچنین ما
UserValidator پیش فرض را تنظیم می کنم تا alphanumeric characters برای ورود نتواند ثبت شود زیرا در قوانین جدیدی که برای ثبت کاربران در سال 2014 توافق شده است نام کاربری از ایمیل آدرس جدا خواهد بود، به همین دلیل ما مشخص می کنیم که این فیلد باید ایمیل آدرس باشد نه نام کاربری.
Authentication
در ابتدا ما باید از UserManager<AppUser> یک شی برای دسترسی به AuthController ایجاد کنیم.
public class AuthController : Controller
{
private readonly UserManager<AppUser> userManager;
public AuthController()
: this (Startup.UserManagerFactory.Invoke())
{
}
public AuthController(UserManager<AppUser> userManager)
{
this.userManager = userManager;
}
// ...
ما باید مطمئن شویم در پایان هر درخواست underlying Entity Framework را از DbContext ایی که ایجاد کردیم، به صورت صحیح dispose می کنیم:
protected override void Dispose(bool disposing)
{
if (disposing && userManager != null)
{
userManager.Dispose();
}
base.Dispose(disposing);
}
حال ما احراز هویت را که در مقاله قبلی به صورت Hard Code نوشته بودیم به صورت زیر برای UserManager تغییر می دهیم:
[HttpPost]
public async Task<ActionResult> LogIn(LogInModel model)
{
if (!ModelState.IsValid)
{
return View();
}
var user = await userManager.FindAsync(model.Email, model.Password);
if (user != null)
{
var identity = await userManager.CreateIdentityAsync(
user, DefaultAuthenticationTypes.ApplicationCookie);
GetAuthenticationManager().SignIn(identity);
return Redirect(GetRedirectUrl(model.ReturnUrl));
}
// user authN failed
ModelState.AddModelError("", "Invalid email or password");
return View();
}
1- در ابتدا ما تلاش می کنیم تا user را با استفاده از userManager.FindAsync پیدا کنیم
2- اگر کاربری با این مشخصات وجود داشت، ما یک claims identity برای کاربری که می تواند به AuthenticationManager انتقال داده شود ایجاد می کنیم. این claims شامل تمامی اطلاعاتی است که شما قبلا ذخیره کرده اید.
3- در نهایت ما با استفاده از احراز هویت به روش cookie (cookie authentication middleware) را انجام می دهیم و کاربر را به وسیله SignIn(identity) ، SignIn می کنیم .
Registration
هر چند بدون طراحی این بخش می توانیم سیستم خود را تست کنیم اما برای کامل شدن این کار را انجام می دهیم.
در ابتدا یک view model برای نمایش فرم ثبت نام ایجاد می کنیم.
public class RegisterModel
{
[Required]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
[Required]
public string Country { get; set; }
}
سپس یک Action برای ثبت اطلاعات در AuthController اضافه می کنیم:
[HttpGet]
public ActionResult Register()
{
return View();
}
[HttpPost]
public async Task<ActionResult> Register(RegisterModel model)
{
if (!ModelState.IsValid)
{
return View();
}
var user = new AppUser
{
UserName = model.Email,
Country = model.Country
};
var result = await userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignIn(user);
return RedirectToAction("index", "home");
}
foreach (var error in result.Errors)
{
ModelState.AddModelError("", error);
}
return View();
}
برای ساخت کاربر ما userManager.CreateAsync را فراخوانی کنیم تا شی AppUser را انتقال دهد (ASP.NET Identity پسورد را hash می کند و امنیت را برای ذخیره سازی اطلاعات فراهم می کند)
ما نیاز داریم که اطلاعات را برای لاگین و ثبت نام ثبت کنیم بنابراین Method را به صورت زیر تغییر می دهیم:
private async Task SignIn(AppUser user)
{
var identity = await userManager.CreateIdentityAsync(
user, DefaultAuthenticationTypes.ApplicationCookie);
da
GetAuthenticationManager().SignIn(identity);
}
در آخر ما register view را ایجاد می کنیم:
@model NakedIdentity.Mvc.ViewModels.RegisterModel
@{
ViewBag.Title = "Register";
}
<h2>Register</h2>
@Html.ValidationSummary(false)
@using (Html.BeginForm())
{
@Html.EditorForModel()
<p>
<button type="submit">Register</button>
</p>
}
Run the application
اگر برنامه را اجرا کنید و به صفحه home بروید، خطایی را دریافت خواهید کرد.
اگر خاطرتان باشد در آموزش ASP.NET Identity 1 ما پیامی را برای نمایش کشور کاربر لاگشن کرده ایجاد کردیم، که نام کشور کاربر را از "Country" claim ذخیره شده در کوکی می خواندیم.
Hello Esmaeil. How's the weather in Iran?
خوب ما برای نمایش کشور کاربر لاگین کرده می توانیم، نام کشور کاربر را پس از لاگین کردن به صورت claim ذخیره کنیم و پس از آن هر وقت احتیاج به نام کشور کاربر خود داشتیم آن را به سادگی بخوانیم.
private async Task SignIn(AppUser user)
{
var identity = await userManager.CreateIdentityAsync(
user, DefaultAuthenticationTypes.ApplicationCookie);
identity.AddClaim(new Claim(ClaimTypes.Country, user.Country));
GetAuthenticationManager().SignIn(identity);
}
یک راه بهتر این است که ما ClaimsIdentityFactory خود را ایجاد کنیم و یا به نوعی override کنیم:
public class AppUserClaimsIdentityFactory : ClaimsIdentityFactory<AppUser>
{
public override async Task<ClaimsIdentity> CreateAsync(
UserManager<AppUser> manager,
AppUser user,
string authenticationType)
{
var identity = await base.CreateAsync(manager, user, authenticationType);
identity.AddClaim(new Claim(ClaimTypes.Country, user.Country));
return identity;
}
}
تنها کاری که لازم است این است که UserManagerFactory را در کلاس Startup.cs بروزرسانی کنیم:
UserManagerFactory = () =>
{
//...
// use out custom claims provider
usermanager.ClaimsIdentityFactory = new AppUserClaimsIdentityFactory();
return usermanager;
};
پروژه را Rebuild کنید.
ذخیره کردن اطلاعات بیشتر برای کاربر
فرض کنید حال می خواهیم علاوه بر نام کشور کاربر سن کاربر را نیز در Claims ذخیره کنیم، خوب به دلیل تغییراتی که در کد دادیم این کار بسیار ساده خواهد بود:
public int Age { get; set; }
همین کار را برای RegisterModel انجام می دهیم:
[Required]
public int Age { get; set; }
اکشن Register را نیز برای مپ کردن اطلاعات ووردی به صورت زیر تغییر دهید:
var user = new AppUser
{
UserName = model.Email,
Country = model.Country,
Age = model.Age
};
حال اگر پروژه را اجرا کنید خطای زیر را دریافت می کنید:
The model backing the 'IdentityDbContext`1' context has changed since the database was created. Consider using Code First Migrations to update the database.
Entity Framework به اندازه کافی باهوش است که بفهمد مدل شما تغییر کرده اما دیتابیس هنوز تغییر نکرده است.
در Package Manager Console ویژوال استادیو می توانید دستور بروز رسانی دیتابیس را به صورت زیر اجرا کنید:
PM> Enable-Migrations -EnableAutomaticMigrations
و بعد دستور زیر را اجرا کنید:
PM> Update-Database
حال اگر برنامه را اجرا کنید می توانید Property سن را نیز ثبت کنید و همچنین اگر در SQL Server نگاه کنید می بینید که فیلد age به جدول شما اضافه شده است.
کل کد پروژه را نیز برای شما قرار دادم تا بتوانید بهتر پروژه را بررسی کنید.
password: www.eduonline.ir
عنوان: آموزش Asp.net Identity
توضیحات: آموزش Asp.net Identity
حجم: 376 کیلوبایت
شخصا فکر می کنم کار کردن با ASP.NET Identity برای بیشتر افراد سخت است، شاید دلیلش ارائه شدن قابلیتهای جدیدی است که بسیاری از افراد با آنها در ASP.NET Identity تازه آشنا می شوند.
به همین دلیل سعی خودم را کردم تا بتوانم این مطلب را برای شما بنویسم، انشالله که مفید واقع شود.
نظرات (۷)
با عرض سلام و تشکر از شما
خوشحال هستم که حداقل کار ممکنی که از بنده ساخته است، توانسته مفید واقع شود.
یاعلی
با عرض سلام
موارد اصلی این تکنولوژی به صورت کامل آموزش داده شده است. در صورتی که هر یک از موارد برای شما مبهم است می توانید سوالتان مطرح کنید تا شما و سایر دوستان سریعتر به نتیجه مطلوب برسید
باتشکر
اولین سوالی که برام پیش اومده اینه که چطور میشه پیغام های مرتبط با اعاتبارسنجی سمت کلاینت کلاس های ApplicationUser و ApplicationRole رو به فارسی برگردوند
به عنوان مثال بنده در بخش ایجاد نقش در پروژه ام نتونستم پیغام خطای مرتبط با الزامی بودن نام نقش رو به فارسی برگردونم.
تصاویر رو میذارم ببینید
http://uupload.ir/files/di9a_1.jpg
http://uupload.ir/files/auq7_2.jpg
با عرض سلام
مطلبی در این خصوص در چند روز آتی بر روی سایت قرار خواهد گرفت
موفق باشید
با عرض سلام
karetoon harf nadare khoda ghovat
ishala khoda avazetoon bede
merc