22
ن مقاله : عنواشی کردن آموزش سفارAsp.Net Identity ده خارجیه دا با پایگاویسان مرجع تخصصی برنامه ن وتنظیم کننده :یه تهwww.barnamenevisan.org [email protected] Asp.Net Identity ده ازستفابلیت ای و قانای توا تا به مال طراحی شده استن دلی به ایStorage Provider های های برنامه مختلف را درASP.Net یتوانیم از ما بدهد . ما م ، بهIdentity Provider ی که با هایNet Framework. یتوانیم م کنیم و همستفاده شده است ا عرضهProvider های خ کنیما طراحی ودمان ر. ین مقاله در ایجادرسی ا به برProvider خواهیم پرداخت سفارشی های. یجاد برای اساسییل ا دو دلProvider جود دارد سفارشی و های. ذخیره ما نیاز بهعاتزی اط ساIdentity درdata source راداریم که توسط ایIdentity Provider ای که درNet Framework. بانی نمیجود دارد ، پشتی و هایه داده شود ، مثل پایگاMySQL ه داده ، یک پایگاOracle یا دیگر هایبع داده منا. عاتید اط ما باIdentity ده از یکستفا ا با راDatabase schema ی که با اProvider ، Database schema مات کنیم است ، مدیریفاوت مت. در مثالی که در یککربندی و پیاده سازی ، ما قصد پی کرد خواهیدده مشاهمه مقاله اداIdentity Provider ده ازستفا ا سفارشی باASP.Net MVC 5 را داریم. یجاد پروژه اASP.Net MVC : Visual Studio رده و یک پروژهباز ک راASP.NET Web application کنید ویجاد اMVC Template راتخاب کنی ان د.

یجراخ هداد هاگیاپ اب Asp.Net Identity ندرک یشرافس شزومآ ... · Identity Provider کی یدنبرکیپ و یزاس هدایپ د ق ام ، درک

  • Upload
    others

  • View
    5

  • Download
    0

Embed Size (px)

Citation preview

Page 1: یجراخ هداد هاگیاپ اب Asp.Net Identity ندرک یشرافس شزومآ ... · Identity Provider کی یدنبرکیپ و یزاس هدایپ د ق ام ، درک

با پایگاه داده خارجی Asp.Net Identityآموزش سفارشی کردن عنوان مقاله :

تهیه وتنظیم کننده : مرجع تخصصی برنامه نویسان

www.barnamenevisan.org [email protected]

Asp.Net Identity به این دلیل طراحی شده است تا به ما توانایی و قابلیت استفاده از Storage Provider های

Net هایی که باIdentity Provider، به ما بدهد . ما میتوانیم از ASP.Net مختلف را در برنامه های

Framework. عرضه شده است استفاده کنیم و هم میتوانیم Providerدر این مقاله .ودمان را طراحی کنیم های خ

. های سفارشی خواهیم پرداخت Provider به بررسی ایجاد

. های سفارشی وجود داردProvider دو دلیل اساسی برای ایجاد

ای که در Identity Provider ای راداریم که توسطdata source در Identity سازی اطالعاتما نیاز به ذخیره

Net Framework. شود ، مثل پایگاه داده هایوجود دارد ، پشتیبانی نمی MySQL یک پایگاه داده ، Oracle یا

. منابع داده های دیگر

ما Provider ، Database schema ای که با Database schema را با استفاده از یک Identity ما باید اطالعات

. متفاوت است ، مدیریت کنیم

Identity Provider ادامه مقاله مشاهده خواهید کرد ، ما قصد پیاده سازی و پیکربندی یک در مثالی که در

. را داریم ASP.Net MVC 5 سفارشی با استفاده از

: ASP.Net MVC ایجاد پروژه

Visual Studio راباز کرده و یک پروژه ASP.NET Web application ایجاد کنید و MVC Template را

. دانتخاب کنی

Page 2: یجراخ هداد هاگیاپ اب Asp.Net Identity ندرک یشرافس شزومآ ... · Identity Provider کی یدنبرکیپ و یزاس هدایپ د ق ام ، درک

با پایگاه داده خارجی Asp.Net Identityآموزش سفارشی کردن عنوان مقاله :

تهیه وتنظیم کننده : مرجع تخصصی برنامه نویسان

www.barnamenevisan.org [email protected]

را برای ساختن یک کاربر جدید Registerرا میزنیم تا برنامه اجرا شود . بعد اجرا F5 بعد از ایجاد شدن پروژه

: میزنیم . مراحل زیر را دنبال کنید

: را بزنید Register بعد از پر کردن فیلد های مربوط به ثبت نام

Page 3: یجراخ هداد هاگیاپ اب Asp.Net Identity ندرک یشرافس شزومآ ... · Identity Provider کی یدنبرکیپ و یزاس هدایپ د ق ام ، درک

با پایگاه داده خارجی Asp.Net Identityآموزش سفارشی کردن عنوان مقاله :

تهیه وتنظیم کننده : مرجع تخصصی برنامه نویسان

www.barnamenevisan.org [email protected]

: آن را باز کنید root کلیک راست کرده و فولدر App_Data روی فولدر Solution Explorer در

ساخته aspnet-AspNetIdentity-20160402093629 خواهید دید که بعد از اجرای برنامه پایگاه داده ایی با نام

...و username ،Password از این پایگاه داده برای ذخیره سازی اطالعات امنیتی نظیر asp.netخواهد شد ،

. فاده خواهد کرداست

در پایگاه داده ساخته نشده است اما به آن aspnet-AspNetIdentity-2016040209362 توجه داشته باشید که

Customize Identity منتقل میکنیم و آن برای SQL Server ضمیمه شده است . پس ، ما پایگاه داده را به

. کنیماستفاده می

کلیک SQL Server Object Explorer کلیک و سپس روی View و، رویدر قسمت من Visual Studio در

: را باز کنید Table کنید ، پایگاه داده خود را انتخاب کرده و فولدر

Page 4: یجراخ هداد هاگیاپ اب Asp.Net Identity ندرک یشرافس شزومآ ... · Identity Provider کی یدنبرکیپ و یزاس هدایپ د ق ام ، درک

با پایگاه داده خارجی Asp.Net Identityآموزش سفارشی کردن عنوان مقاله :

تهیه وتنظیم کننده : مرجع تخصصی برنامه نویسان

www.barnamenevisan.org [email protected]

: ساخته شده است Table پنج

AspNetRoles, AspNetUserClaims, AspNetUserLogins, AspNetUserRoles, AspNetUsers .

: های پایگاه داده خود داشته باشیمmodel ما میتوانیم یک نگاه اجمالی به database diagram با ایجاد یک

Page 5: یجراخ هداد هاگیاپ اب Asp.Net Identity ندرک یشرافس شزومآ ... · Identity Provider کی یدنبرکیپ و یزاس هدایپ د ق ام ، درک

با پایگاه داده خارجی Asp.Net Identityآموزش سفارشی کردن عنوان مقاله :

تهیه وتنظیم کننده : مرجع تخصصی برنامه نویسان

www.barnamenevisan.org [email protected]

کنید تنظیم را برای پایگاه داده خود ConnectionString را باز کرده و مشخصات web.Config در نهایت ، فایل

:

: رویمیرا میزنیم تا برنامه اجرا شود ، بعد به سراغ ایجاد یک کاربر جدید م F5 حال

خارجی آماده است . در مرحله بعد ، چگونگی سفارشی کردن Storage درحال حاضر برنامه ما، برای استفاده از یک

. پایگاه داده خارجی را برای شما بیان خواهیم کرد

: Identity Library Project ایجاد

: یممیگذار IdentityLibrary ایجاد کرده و نام آن را class library یک

: را انتخاب کنید Manage NuGet Packages کلیک راست کرده و References روی

Microsoft.AspNet.Identity.Core و Microsoft.AspNet.Identity.EntityFramework را نصب کنید .

Page 6: یجراخ هداد هاگیاپ اب Asp.Net Identity ندرک یشرافس شزومآ ... · Identity Provider کی یدنبرکیپ و یزاس هدایپ د ق ام ، درک

با پایگاه داده خارجی Asp.Net Identityآموزش سفارشی کردن عنوان مقاله :

تهیه وتنظیم کننده : مرجع تخصصی برنامه نویسان

www.barnamenevisan.org [email protected]

IdentityUser از کالس این ، کنید ایجاد کاربران اطالعات نگهداری برای IdentityUser یک کالس با نام

: کندبری میارث

Page 7: یجراخ هداد هاگیاپ اب Asp.Net Identity ندرک یشرافس شزومآ ... · Identity Provider کی یدنبرکیپ و یزاس هدایپ د ق ام ، درک

با پایگاه داده خارجی Asp.Net Identityآموزش سفارشی کردن عنوان مقاله :

تهیه وتنظیم کننده : مرجع تخصصی برنامه نویسان

www.barnamenevisan.org [email protected]

: را برای نگهداری اطالعات در مورد نقش کاربران را ایجاد کنید IdentityRole کالس

: بصورت پیش فرض از این کالس استفاده خواهد کرد Asp.Net MVCایجاد کنید ، UserStore یک کالس با نام

var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));

Page 8: یجراخ هداد هاگیاپ اب Asp.Net Identity ندرک یشرافس شزومآ ... · Identity Provider کی یدنبرکیپ و یزاس هدایپ د ق ام ، درک

با پایگاه داده خارجی Asp.Net Identityآموزش سفارشی کردن عنوان مقاله :

تهیه وتنظیم کننده : مرجع تخصصی برنامه نویسان

www.barnamenevisan.org [email protected]

: آن را پیاده سازی میکنیم Storage Provider اما با این وجود ، ما برای سفارشی کردن

: کنیممی RoleStore ، کالسی با نام IRoleIdentity برای پیاده سازی

Page 9: یجراخ هداد هاگیاپ اب Asp.Net Identity ندرک یشرافس شزومآ ... · Identity Provider کی یدنبرکیپ و یزاس هدایپ د ق ام ، درک

با پایگاه داده خارجی Asp.Net Identityآموزش سفارشی کردن عنوان مقاله :

تهیه وتنظیم کننده : مرجع تخصصی برنامه نویسان

www.barnamenevisan.org [email protected]

: Entity Framework dataModel ایجاد یک

ADO.NET Entity Data را بزنید ، add new item راست کلیک کرده و IdentityLibrary روی پروژه

Model را انتخاب کرده و Add را بزنید :

Code First From Database را انتخاب کرده و Next را بزنید :

: جدید ایجاد کنیم connection اب کنیم یا اینکه یکتوانیم آن را انتخداریم می data connection اگه ما یک

Page 10: یجراخ هداد هاگیاپ اب Asp.Net Identity ندرک یشرافس شزومآ ... · Identity Provider کی یدنبرکیپ و یزاس هدایپ د ق ام ، درک

با پایگاه داده خارجی Asp.Net Identityآموزش سفارشی کردن عنوان مقاله :

تهیه وتنظیم کننده : مرجع تخصصی برنامه نویسان

www.barnamenevisan.org [email protected]

Server Name را انتخاب کنید ، از Windows Authentication یا SQL Server Authentication استفاده

کنید ،

: را بزنید Ok سپس پایگاه داده مورد نظر را انتخاب کرده و

Page 11: یجراخ هداد هاگیاپ اب Asp.Net Identity ندرک یشرافس شزومآ ... · Identity Provider کی یدنبرکیپ و یزاس هدایپ د ق ام ، درک

با پایگاه داده خارجی Asp.Net Identityآموزش سفارشی کردن عنوان مقاله :

تهیه وتنظیم کننده : مرجع تخصصی برنامه نویسان

www.barnamenevisan.org [email protected]

: ما را تولید کند model جداول پایگاه داده را چک انتخاب کرده تا

Page 12: یجراخ هداد هاگیاپ اب Asp.Net Identity ندرک یشرافس شزومآ ... · Identity Provider کی یدنبرکیپ و یزاس هدایپ د ق ام ، درک

با پایگاه داده خارجی Asp.Net Identityآموزش سفارشی کردن عنوان مقاله :

تهیه وتنظیم کننده : مرجع تخصصی برنامه نویسان

www.barnamenevisan.org [email protected]

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

: را پیکربندی میکنیم ASP.Net Client ، Custom Identity Library برای هدف قرار دادن

Page 13: یجراخ هداد هاگیاپ اب Asp.Net Identity ندرک یشرافس شزومآ ... · Identity Provider کی یدنبرکیپ و یزاس هدایپ د ق ام ، درک

با پایگاه داده خارجی Asp.Net Identityآموزش سفارشی کردن عنوان مقاله :

تهیه وتنظیم کننده : مرجع تخصصی برنامه نویسان

www.barnamenevisan.org [email protected]

: Custom Identity پیاده سازی

: UserStore پیاده سازی •

/// <summary> /// Class that implements the key ASP.NET Identity user store iterfaces /// </summary> public class UserStore<T> : IUserRoleStore<T>, IUserStore<T>, IUserPasswordStore<T>,

Page 14: یجراخ هداد هاگیاپ اب Asp.Net Identity ندرک یشرافس شزومآ ... · Identity Provider کی یدنبرکیپ و یزاس هدایپ د ق ام ، درک

با پایگاه داده خارجی Asp.Net Identityآموزش سفارشی کردن عنوان مقاله :

تهیه وتنظیم کننده : مرجع تخصصی برنامه نویسان

www.barnamenevisan.org [email protected]

IUserEmailStore<T>, IUserLockoutStore<T, string>, IUserTwoFactorStore<T, string> where T : IdentityUser { private readonly UserRepository<T> _userTable; private readonly UserRolesRepository _userRolesTable; public UserStore(DatabaseContext databaseContext) { _userTable = new UserRepository<T>(databaseContext); _userRolesTable = new UserRolesRepository(databaseContext); } public Task CreateAsync(T user) { if (user == null) { throw new ArgumentNullException(“user”); } return Task.Run(() => _userTable.Insert(user)); } public Task<T> FindByIdAsync(string userId) { if (string.IsNullOrEmpty(userId)) { throw new ArgumentException(“Null or empty argument: userId”); } return Task.Run(() => _userTable.GeTById(userId)); } public Task<bool> GetTwoFactorEnabledAsync(T user) { return Task.FromResult(user.TwoFactorEnabled); } public Task<T> FindByNameAsync(string userName) { if (string.IsNullOrEmpty(userName)) { throw new ArgumentException(“Null or empty argument: userName”);

Page 15: یجراخ هداد هاگیاپ اب Asp.Net Identity ندرک یشرافس شزومآ ... · Identity Provider کی یدنبرکیپ و یزاس هدایپ د ق ام ، درک

با پایگاه داده خارجی Asp.Net Identityآموزش سفارشی کردن عنوان مقاله :

تهیه وتنظیم کننده : مرجع تخصصی برنامه نویسان

www.barnamenevisan.org [email protected]

} return Task.Run(() => _userTable.GeTByName(userName)); } public Task<IList<string>> GetRolesAsync(T user) { if (user == null) { throw new ArgumentNullException(“user”); } return Task.Run(() => _userRolesTable.FindByUserId(user.Id)); } public Task<string> GetPasswordHashAsync(T user) { return Task.Run(() => _userTable.GetPasswordHash(user.Id)); } public Task SetPasswordHashAsync(T user, string passwordHash) { return Task.Run(() => user.PasswordHash = passwordHash); } public Task<T> FindByEmailAsync(string email) { if (String.IsNullOrEmpty(email)) { throw new ArgumentNullException(“email”); } return Task.Run(() => _userTable.GeTByEmail(email)); } public Task<string> GetEmailAsync(T user) { return Task.FromResult(user.Email); } public Task<int> GetAccessFailedCountAsync(T user) { return Task.FromResult(user.AccessFailedCount);

Page 16: یجراخ هداد هاگیاپ اب Asp.Net Identity ندرک یشرافس شزومآ ... · Identity Provider کی یدنبرکیپ و یزاس هدایپ د ق ام ، درک

با پایگاه داده خارجی Asp.Net Identityآموزش سفارشی کردن عنوان مقاله :

تهیه وتنظیم کننده : مرجع تخصصی برنامه نویسان

www.barnamenevisan.org [email protected]

} public Task<bool> GetLockoutEnabledAsync(T user) { return Task.FromResult(user.LockoutEnabled); } public Task<DateTimeOffset> GetLockoutEndDateAsync(T user) { return Task.FromResult(user.LockoutEndDateUtc.HasValue ? new DateTimeOffset(DateTime.SpecifyKind(user.LockoutEndDateUtc.Value, DateTimeKind.Utc)) : new DateTimeOffset()); } public Task SetLockoutEnabledAsync(T user, bool enabled) { user.LockoutEnabled = enabled; return Task.Run(() => _userTable.Update(user)); } public Task SetLockoutEndDateAsync(T user, DateTimeOffset lockoutEnd) { throw new NotImplementedException(); } public Task SetTwoFactorEnabledAsync(T user, bool enabled) { throw new NotImplementedException(); } public Task DeleteAsync(T user) { throw new NotImplementedException(); } public Task<int> IncrementAccessFailedCountAsync(T user) { throw new NotImplementedException(); }

Page 17: یجراخ هداد هاگیاپ اب Asp.Net Identity ندرک یشرافس شزومآ ... · Identity Provider کی یدنبرکیپ و یزاس هدایپ د ق ام ، درک

با پایگاه داده خارجی Asp.Net Identityآموزش سفارشی کردن عنوان مقاله :

تهیه وتنظیم کننده : مرجع تخصصی برنامه نویسان

www.barnamenevisan.org [email protected]

public Task ResetAccessFailedCountAsync(T user) { throw new NotImplementedException(); } public Task<bool> GetEmailConfirmedAsync(T user) { throw new NotImplementedException(); } public Task SetEmailAsync(T user, string email) { throw new NotImplementedException(); } public Task SetEmailConfirmedAsync(T user, bool confirmed) { throw new NotImplementedException(); } public Task<bool> IsInRoleAsync(T user, string roleName) { throw new NotImplementedException(); } public Task RemoveFromRoleAsync(T user, string roleName) { throw new NotImplementedException(); } public Task<bool> HasPasswordAsync(T user) { throw new NotImplementedException(); } public Task UpdateAsync(T user) { throw new NotImplementedException(); } public Task AddToRoleAsync(T user, string roleName) { throw new NotImplementedException();

Page 18: یجراخ هداد هاگیاپ اب Asp.Net Identity ندرک یشرافس شزومآ ... · Identity Provider کی یدنبرکیپ و یزاس هدایپ د ق ام ، درک

با پایگاه داده خارجی Asp.Net Identityآموزش سفارشی کردن عنوان مقاله :

تهیه وتنظیم کننده : مرجع تخصصی برنامه نویسان

www.barnamenevisan.org [email protected]

} public void Dispose() { //throw new NotImplementedException(); } }

: سازی آنو پیاده UserRepository ایجاد یک کالس •

public class UserRepository<T> where T : IdentityUser { private readonly DatabaseContext _databaseContext; public UserRepository(DatabaseContext databaseContext) { _databaseContext = databaseContext; } internal T GeTByName(string userName) { var user = _databaseContext.AspNetUsers.SingleOrDefault(u => u.UserName == userName); if (user != null) { T result = (T)Activator.CreateInstance(typeof(T)); result.Id = user.Id;

Page 19: یجراخ هداد هاگیاپ اب Asp.Net Identity ندرک یشرافس شزومآ ... · Identity Provider کی یدنبرکیپ و یزاس هدایپ د ق ام ، درک

با پایگاه داده خارجی Asp.Net Identityآموزش سفارشی کردن عنوان مقاله :

تهیه وتنظیم کننده : مرجع تخصصی برنامه نویسان

www.barnamenevisan.org [email protected]

result.UserName = user.UserName; result.PasswordHash = user.PasswordHash; result.SecurityStamp = user.SecurityStamp; result.Email = result.Email; result.EmailConfirmed = user.EmailConfirmed; result.PhoneNumber = user.PhoneNumber; result.PhoneNumberConfirmed = user.PhoneNumberConfirmed; result.LockoutEnabled = user.LockoutEnabled; result.LockoutEndDateUtc = user.LockoutEndDateUtc; result.AccessFailedCount = user.AccessFailedCount; return result; } return null; } internal T GeTByEmail(string email) { var user = _databaseContext.AspNetUsers.SingleOrDefault(u => u.Email == email); if (user != null) { T result = (T)Activator.CreateInstance(typeof(T)); result.Id = user.Id; result.UserName = user.UserName; result.PasswordHash = user.PasswordHash; result.SecurityStamp = user.SecurityStamp; result.Email = result.Email; result.EmailConfirmed = user.EmailConfirmed; result.PhoneNumber = user.PhoneNumber; result.PhoneNumberConfirmed = user.PhoneNumberConfirmed; result.LockoutEnabled = user.LockoutEnabled; result.LockoutEndDateUtc = user.LockoutEndDateUtc; result.AccessFailedCount = user.AccessFailedCount; return result; } return null; } internal int Insert(T user) { _databaseContext.AspNetUsers.Add(new AspNetUsers { Id = user.Id,

Page 20: یجراخ هداد هاگیاپ اب Asp.Net Identity ندرک یشرافس شزومآ ... · Identity Provider کی یدنبرکیپ و یزاس هدایپ د ق ام ، درک

با پایگاه داده خارجی Asp.Net Identityآموزش سفارشی کردن عنوان مقاله :

تهیه وتنظیم کننده : مرجع تخصصی برنامه نویسان

www.barnamenevisan.org [email protected]

UserName = user.UserName, PasswordHash = user.PasswordHash, SecurityStamp = user.SecurityStamp, Email = user.Email, EmailConfirmed = user.EmailConfirmed, PhoneNumber = user.PhoneNumber, PhoneNumberConfirmed = user.PhoneNumberConfirmed, LockoutEnabled = user.LockoutEnabled, LockoutEndDateUtc = user.LockoutEndDateUtc, AccessFailedCount = user.AccessFailedCount }); return _databaseContext.SaveChanges(); } /// <summary> /// Returns an T given the user’s id /// </summary> /// <param name=”userId”>The user’s id</param> /// <returns></returns> public T GeTById(string userId) { var user = _databaseContext.AspNetUsers.Find(userId); T result = (T)Activator.CreateInstance(typeof(T)); result.Id = user.Id; result.UserName = user.UserName; result.PasswordHash = user.PasswordHash; result.SecurityStamp = user.SecurityStamp; result.Email = result.Email; result.EmailConfirmed = user.EmailConfirmed; result.PhoneNumber = user.PhoneNumber; result.PhoneNumberConfirmed = user.PhoneNumberConfirmed; result.LockoutEnabled = user.LockoutEnabled; result.LockoutEndDateUtc = user.LockoutEndDateUtc; result.AccessFailedCount = user.AccessFailedCount; return result; } /// <summary> /// Return the user’s password hash /// </summary> /// <param name=”userId”>The user’s id</param>

Page 21: یجراخ هداد هاگیاپ اب Asp.Net Identity ندرک یشرافس شزومآ ... · Identity Provider کی یدنبرکیپ و یزاس هدایپ د ق ام ، درک

با پایگاه داده خارجی Asp.Net Identityآموزش سفارشی کردن عنوان مقاله :

تهیه وتنظیم کننده : مرجع تخصصی برنامه نویسان

www.barnamenevisan.org [email protected]

/// <returns></returns> public string GetPasswordHash(string userId) { var user = _databaseContext.AspNetUsers.FirstOrDefault(u => u.Id == userId); var passHash = user != null ? user.PasswordHash : null; return passHash; } /// <summary> /// Updates a user in the Users table /// </summary> /// <param name=”user”></param> /// <returns></returns> public int Update(T user) { var result = _databaseContext.AspNetUsers.FirstOrDefault(u => u.Id == user.Id); if (result != null) { result.UserName = user.UserName; result.PasswordHash = user.PasswordHash; result.SecurityStamp = user.SecurityStamp; result.Email = result.Email; result.EmailConfirmed = user.EmailConfirmed; result.PhoneNumber = user.PhoneNumber; result.PhoneNumberConfirmed = user.PhoneNumberConfirmed; result.LockoutEnabled = user.LockoutEnabled; result.LockoutEndDateUtc = user.LockoutEndDateUtc; result.AccessFailedCount = user.AccessFailedCount; return _databaseContext.SaveChanges(); } return 0; } }

: و پیاده سازی آن UserRolesRepository ایجاد یک کالس •

Page 22: یجراخ هداد هاگیاپ اب Asp.Net Identity ندرک یشرافس شزومآ ... · Identity Provider کی یدنبرکیپ و یزاس هدایپ د ق ام ، درک

با پایگاه داده خارجی Asp.Net Identityآموزش سفارشی کردن عنوان مقاله :

تهیه وتنظیم کننده : مرجع تخصصی برنامه نویسان

www.barnamenevisan.org [email protected]

. آماده است IdentityLibrary حال ، برنامه ما برای استفاده از