آموزش احراز هویت user identity بخش دوم
در این مقاله قصد داریم گام به گام مراحل کاربا احراز هویت user identity را به همراه پایگاه داده بررسی کنیم. با ما همراه باشید تا به سادگی یک برنامه بر این پایه ایجاد نمایید.
در اين بخش ادامه بخش اول را خواهيم داشت و ميخواهيم به جاي شناسه و پسورد hardcode درون کلاس ها از ديتا بيس استفاده کنيم. خب سريع شروع کنيم :
1) نصب identity با کد زير:
PM > Install-Package Microsoft.AspNet.Identity.EntityFramework
2) در پوشه مد يک کلاس با نام ApplicationUser ايجاد کنيد و محتواي آن را به صورت زير قرار دهيد.(ميخواهيم فقط نام کشور را بياوريم)
public class ApplicationUser : IdentityUser
{
public string Country { get; set; }
}
3) در پوشه مدل کلاس ApplicationDbContext را ايجاد ميکنيم و محتواي آن را مطابق زير مقداردهي ميکنيم.
public class ApplicationDbContext: IdentityDbContext
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
}
4) براي اتصال به پايگاه داده connection string خود را مطابق زير به web.config اضافه کنيد:
<connectionStrings>
<add name="DefaultConnection"
connectionString="Data Source=.;Initial Catalog=chat;Integrated Security=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
5) به کلاس Startup.cs برويد و آن را به صورت زير بازنويسي کنيد:
public class Startup
{
public static Func> UserManagerFactory { get; private set; }
public void Configuration(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "ApplicationCookie",
LoginPath = new PathString("/Account/Login")
});
// configure the user manager
UserManagerFactory = () =>
{
var usermanager = new UserManager(
new UserStore(new ApplicationDbContext()));
// allow alphanumeric characters in username
usermanager.UserValidator = new UserValidator(usermanager)
{
AllowOnlyAlphanumericUserNames = false
};
return usermanager;
};
}
}
6) به کنترلر Account برويد و تکه کد زير را به ابتداي آن اضافه کنيد:
private readonly UserManager userManager;
public AccountController()
: this (Startup.UserManagerFactory.Invoke())
{
}
public AccountController(UserManager userManager)
{
this.userManager = userManager;
}
7) تکه کد زير را نيز به انتهاي کنترلر Account اضافه ميکنيم براي نابود سازي در انتهاي request
protected override void Dispose(bool disposing)
{
if (disposing && userManager != null)
{
userManager.Dispose();
}
base.Dispose(disposing);
}
8) حال بايد با استفاده از کد زير متد login را بازنويسي کنيم:
[HttpPost]
public async Task LogIn(Models.ViewModels.Login 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();
}
همچنين تابع زير را به همين کنترلر اضافه ميکنيم :
private IAuthenticationManager GetAuthenticationManager()
{
var ctx = Request.GetOwinContext();
return ctx.Authentication;
}
9) حال ميخواهيم عضويت را ايجاد کنيم. ابتدا يک ويو مدل براي آن مينويسيم، به models سپس viewmodels برويد يک کلاس به نام Register ايجاد کنيد و محتواي آن را به صورت زير پر کنيد:
public class Register
{
[Required]
[DataType(DataType.EmailAddress)]
[DisplayName("شناسه")]
public string Email { get; set; }
[Required]
[DataType(DataType.Password)]
[DisplayName("پسورد")]
public string Password { get; set; }
[Required]
[DisplayName("کشور")]
public string Country { get; set; }
}
10) به کنترلر account رفته و دو اکشن زير را به آن اضافه کنيد:
[HttpGet]
public ActionResult Register()
{
return View();
}
[HttpPost]
public async Task Register(Models.ViewModels.Register model)
{
if (!ModelState.IsValid)
{
return View();
}
var user = new ApplicationUser
{
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();
}
11) چون تابع SignIn هم در login و هم register استفاده شده است ميتوانيم آن را refactor کرده و در يک تابع جداگانه بنويسيم.
private async Task SignIn(ApplicationUser user)
{
var identity = await userManager.CreateIdentityAsync(
user, DefaultAuthenticationTypes.ApplicationCookie);
GetAuthenticationManager().SignIn(identity);
}
در مرحله ده از Refactore شده مرحله يازده استفاده شده اما در قسمت 8 متد login ، refactore نشده پس آن را نيز به صورت زير بازنويسي ميکنيم:
[HttpPost]
public async Task LogIn(Models.ViewModels.Login model)
{
if (!ModelState.IsValid)
{
return View();
}
var user = await userManager.FindAsync(model.Email, model.Password);
if (user != null)
{
await SignIn(user);
return Redirect(GetRedirectUrl(model.ReturnUrl));
}
// user authN failed
ModelState.AddModelError("", "Invalid email or password");
return View();
}
12) ويو register را ايجاد و محتواي آن را به صورت زير قرار ميدهيم:
@model user_identity.Models.ViewModels.Register
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>عضويت</h2>
@Html.ValidationSummary(false)
@using (Html.BeginForm())
{
@Html.EditorForModel()
<p>
<button type="submit">عضويت</button>
</p>
}
13) حال براي نمايش نام کشور بعد از ورود بايد تابع SignIn را بازنويسي کنيم:
var identity = await userManager.CreateIdentityAsync(
user, DefaultAuthenticationTypes.ApplicationCookie);
identity.AddClaim(new Claim(ClaimTypes.Country, user.Country));
GetAuthenticationManager().SignIn(identity);
14) کلاس AppUserClaimsIdentityFactory را در پوشه identity ايجاد و آن را به صورت زير بازنويسي کنيد:
public class AppUserClaimsIdentityFactory : ClaimsIdentityFactory
{
public async override Task CreateAsync(UserManager manager,
ApplicationUser user, string authenticationType)
{
var identity = await base.CreateAsync(manager, user, authenticationType);
identity.AddClaim(new Claim(ClaimTypes.Country, user.Country));
return identity;
}
}
15) به startup.cs ميرويم و کد زير را قبل از return usermanager; در تابع public void Configuration(IAppBuilder app) قرار ميدهيم:
// use out custom claims provider
usermanager.ClaimsIdentityFactory = new AppUserClaimsIdentityFactory();
16) حالا ميخواهيم ويژگي هاي کاربر را زياد کنيم مثلا الان ميخواهيم ويژگي سن را براي کاربر اضافه کنيم به ApplicationUser در پوشه Models برويد و آن را به صورت زير تغيير دهيد:
public class ApplicationUser : IdentityUser
{
public string Country { get; set; }
public int Age { get; set; }
}
17) فايل Register.cs را در پوشه models <- ViewModels باز کنيد و آن را به صورت زير تغيير دهيد تا ويژگي سن هم براي عضويت به سيستم اضافه کردد:
public class Register
{
[Required]
[DataType(DataType.EmailAddress)]
[DisplayName("شناسه")]
public string Email { get; set; }
[Required]
[DataType(DataType.Password)]
[DisplayName("پسورد")]
public string Password { get; set; }
[Required]
[DisplayName("کشور")]
public string Country { get; set; }
[Required]
[DisplayName("سن")]
public int Age { get; set; }
}
18) سپس متد Register در کنترلر Account را ويرايش کنيد و جايي که user در حال پر شدن است را تغيير و ويژگي سن را به آن اضافه کنيد، پس نتيجه تابع به صورت زير خواهد بود:
[HttpPost]
public async Task Register(Models.ViewModels.Register model)
{
if (!ModelState.IsValid)
{
return View();
}
var user = new ApplicationUser
{
UserName = model.Email,
Country = model.Country,
Age = model.Age,
};
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();
}
19) حالا اگه پروژه را اجرا کنيد بعد از ساخت يک user با خطاي زير مواجه ميشيد:
The model backing the 'ApplicationDbContext' context has changed since the database was created. Consider using Code First Migrations to update the database (http://go.microsoft.com/fwlink/?LinkId=238269).
EF متوجه شده است که کلاس ApplicationUser تغيير يافته است اما تغييرات در ديتابيس اعمال نشده است پس نياز است با استفاده از migration ديتا بيس را بر اساس مدل خود به روز کنيد:
پس در کنسول nugget package manager console کد زير را وارد کنيد تا migration خودکار فعال سازي شود:
PM> Enable-Migrations -EnableAutomaticMigrations
سپس براي اعمال تغييرات بر روي ديتا بيس کد زير را وارد کنيد:
PM> Update-Database
کار تمام است!
اميدوارم از اين دو مقاله استفاده کرده باشيد و آشنايي مناسبي با user identity با استفاده از Asp.net mvc پيدا کرده باشيد.
برای دانلود نمونه کد از لینک زیر استفاده کنید. توجه کنید که پکیج ها پاک شده است و هنگام لود کدها باید به اینترنت وصل باشید تا پس از build اول پکیج ها restore شوند.