به نام آن که جان را فکرت آموخت / چراغ دل به نور جان برافروخت
با سلام و تشکر از مطالعه مقالات بنده در کانال ویرگول در این مقاله به بحث در مورد web api و نحوه امن سازی web api ها و مسایل مربوط به Authentication و Authorization پرداخته می شود در مورد JWT صحبت می شود و از Identity مایکروسافت برای احراز هویت استفاده خواهد شد سعی می شود در یک آموزش کاربردی و پروژه محور نحوه ثبت نام کاربر ، لاگین کاربر ،ایجاد و دریافت توکن و احراز هویت از طریق توکن بررسی شده است.ایده این سری مقاله های آموزشی از این موضوع سرچشمه می گیرد که بخشی از خوانندگان وجود دارد که به محتوای نوشتاری آنلاین بهتر پاسخ می دهند و ترجیج می دهند مهارت های جدید را به سرعت از طریق خواندن افزایش دهند.این سری اموزش ها با ارایه پکیج آموزش های کاربردی در خصوص C# asp.net core آغاز می شود که انتظار می رود با واکنش مثبت کاربران همراه شود.
توجه: این مقاله به مرور زمان، ویرایش و یا تکمیل میشود!
تقاضا: در صورتی که با مشکل تایپی، دستوری و یا مفهومی در این مقاله برخورد کردید، از شما دوست عزیز و گرامی، صمیمانه تقاضا میکنم که اینجانب را مطلع کرده، تا نسبت به تصحیح و یا تکمیل آن، در اسرع وقت، اقدام نمایم.
با کمال تشکر
جواد جهانگیری
شماره تلفن همراه: 09149431772
نشانی پست الکترونیکی: javad.jahangiri.niopdc@gmail.com
فیلمهای آموزشی در آپارات:جواد جهانگیری (CTO) - آپارات
فیلم آموزشی در یوتویب: javad jahangiri - YouTube
نسخه مقاله: ۱.۱ - تاریخ بروزرسانی: 1400/09/09
کاراموزان و دانشجویان عزیز منبع اصلی تهیه این مقاله قسمت امنیت شرکت مایکروسافت به شرح ذیل می باشد
همانگونه که مستحضرید این روزها بازار اپلیکیشن های RESTful داغ هستش و دیگر برنامه ها فقط بصورت وب نمی باشد برای مثال برنامه های اندرویدی و یا برنامه های گوشی های ایفون در نظر بگیرد که با سرورهای که بصورت RESTful سرویس می دهند کار می کند و یا میکروسرویس ها در نظر بگیرد که برای ارتباطات خود از تکنولوژی RESTful استفاده می کنند برای ارتباط با این تکنولوژی از یک قالب خاص داده ای استفاده می شو اول با فرمت XML اطلاعات ارسال و دریافت می شود و د رحال حاظر نیز از فرمت JSON استفاده می شود در حقیقت JSON یک قالب دیتای می باشد که فارغ از اینکه در سمت کلاینت و یا سرور از چه زبان برنامه نویسی استفاده می شود برای نقل و اطلاعات داده ها استفاده می شود
مخفف عبارت JavaScript Object Notation (نشانه گذاری شی جاوا اسکریبت) می باشد در حقیقت یک قالب سبک وزن برای دخیره و حمل و نقل دیتا می باشد .
مثال زیر یک شئ با نام “employees” به معنای کارمندان تعریف کرده است که مقدار این شی حاوی آرایهای با ۳ عنصر است. که هر عنصر آرایه یک شئ است که مشخصات یک کارمند را دربر میگیرد.
{ "employees":[ {"firstName":"John", "lastName":"Doe"}, {"firstName":"Anna", "lastName":"Smith"}, {"firstName":"Peter", "lastName":"Jones"} ] }
برای درک توکن JWT ابتدا وارد سایت زیر می شویم :
دقت کنید JWT مخفف JSON Web Token می باشد
در توکن قسمت قرمز رنگ در حقیقت همان Header بوده و قسمت بنفش هم قسمت Payload بوده و قسمت آبی رنگ هم قسمت Signature هستش
دو روش کلی و پرکاربرد اعتبارسنجی سمت سرور، برای برنامههای سمت کاربر وب وجود دارند:
مزیتهای استفادهی از روش مبتنی بر توکن چیست؟
اما JWT یا JSON Web Token چیست؟
توضیح: JSON Web Token یا JWT یک استاندارد وب است (RFC 7519) که روشی فشرده و خود شمول (self-contained) را جهت انتقال امن اطلاعات بین مقاصد مختلف را توسط یک شی JSON تعریف میکند. این اطلاعات قابل تصدیق و اطمینان هستند، از این رو که به صورت دیجیتال امضا میشوند. JWTها توسط یک کلید خصوصی (با استفاده از الگوریتم HMAC) و یا یک جفت کلید خصوصی و عمومی (توسط الگوریتم RSA) قابل امضا شدن هستند.
در این تعریف واژههایی مانند «فشرده» و «خود شمول» بکار رفتهاند:
- «فشرده بودن»: اندازهی شی JSON یک توکن در این حالت کوچک بوده و به سادگی از طریق یک URL و یا پارامترهای POST و یا داخل یک HTTP Header قابل ارسال است و به دلیل کوچک بودن این اندازه انتقال آن نیز سریع است.
- «خود شمول»: بار مفید (payload) این توکن شامل تمام اطلاعات مورد نیاز جهت اعتبارسنجی یک کاربر است تا دیگر نیازی به کوئری گرفتن هر باره از بانک اطلاعاتی نباشد (در این روش مرسوم است که فقط یکبار از بانک اطلاعاتی کوئری گرفته شده و اطلاعات مرتبط با کاربر را امضای دیجیتال کرده و به سمت کاربر ارسال میکنند).
جوتها دارای سه قسمت است و این قسمتها با نقطه از هم جا شدند، مانند: xxxxx.yyyyy.zzzzz که شامل سه بخش: header.payload.signature میباشند و هر بخش با الگوریتم Base64 اینکد میشود. نمونهای از یک توکن جوت:
1eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.XbPfbIHMI6arZ3Y922BhjWgQzWXcXNrz0ogtVhfEd2o
بخش Header:
بخش Header عموما دارای دو قسمت است که نوع توکن و الگوریتم مورد استفاده توسط آن را مشخص میکند. نوع توکن در اینجا JWT است و الگوریتمهای مورد استفاده، عموما HMAC SHA256 و یا RSA هستند. نمونه اطلاعات دیکد شده بخش هدر:
1234{ "alg": "RS256", "typ": "JWT" }
بخش payload:
بخش payload یا «بار مفید» توکن، شامل claims است، منظور از claims اطلاعاتی است در مورد موجودیت مدنظر (عموما کاربر) و یک سری متادیتای اضافی. سه نوع claim وجود دارند:
نوع اول Reserved claims: یک سری اطلاعات مفید و از پیش تعیین شده غیراجباری هستند مانند:iss یا صادر کنند، exp یا تاریخ انقضا، sub یا عنوان (subject) و aud یا مخاطب (audience)
نوع دوم Public claims: میتواند شامل اطلاعاتی باشد که توسط IANA JSON Web Token Registry پیشتر ثبت شدهاست و فضاهای نام آنها تداخلی نداشته باشند.
نوع سوم Private claims: ادعای سفارشی هستند که جهت انتقال دادهها بین مقاصد مختلف مورد استفاده قرار میگیرند.
نمونه اینکد شده بخش payload توکن:
123456{ "exp": 1520507268, "sub": 582946, "name": "ErFUN KH", "admin": true }
در نمونه بالا دو دیتای اول از نوع Reserved claims میباشد و دو دیتای آخر از نوع Private claims.
به طور استاندارد بخش Reserved claims میتونه شامل این موارد باشه:
این مقادیر همینجا تموم نمیشه، میتونید نگاهی به لیست مایکروسافت کنید، ولی بهتره خیلی شلوغش نکنید، مهم همینها هستند که خیلی وقتها استفاده نمیشن نهایتا sub و exp استفاده میکنند.
بخش signature:
تا اینا دیدیم همه دیتاهای با الگوریتم بیس۶۴ اینکد شد که به راحتی تو هرسیستمی دیکد میشه (اگه با این شیوه آشنا نیستید باید بگم فقط کاراکترهای غیر مجاز به حروف تبدیل میکنه، مقاله ویکیپدیا بخونید) و هرکسی میتونه همچین توکنی بسازه و برای ما ارسال کنه ولی نه با وجود بخش سوم (امضا).
همونطوری که میبینید بخش اول (هدر) با بخش دوم (پیلود) جمع شده و بعد با کلید خصوصی (کلید خصوصی فقط در سرور موجوده) رمز میشه، این به عنوان بخش سوم یا امضا توکن ما استفاده میشه، درصورتی که اطاعات پیلود دست کاری بشه امضا برای سرور معتبر نیست، همچنین چون کاربران کلید خصوصی ندارند نمیتونند خودشون توکن تولید کنند.
همینطور درنظر داسته باشید اطلاعات حساس مثل پسورد یا... داخل توکن نذارید چون هرکسی میتونه به سادگی توکن باز کنه و دیتای داخلش بخونه، ولی اگر واقعا نیازه اطلاعات حساس داخلش بذارید باید از JWE استفاده کنید.
نکته:
توجه شود با عنایت به اینکه اطلاعات در توکن Jwtرمز نشده و فقط بصورت base64 اینکد می شود لذا ما در سامانه های که نیاز به امنیت بیشتری دارند از پروتکل https برای زمز نگاری اطلاعات استفاده می کنیم
1.ابتدا کاربر به نام کاربری و رمز صحیح در سامانه ما login می کند
2.در صورت موفق بودن login به سامانه برنامه یک توکن jwt ایجاد می کند و این توکن را به سمت کلاینت ارسال می کند در توکن در امضا اطلاعات header و payload با یک کلید رمز می شود توجه شود اطلاعات header و Payload خودشان رمز نشده و بصورت base64 فقط encode می شود و براحتی می شود این اطلاعات را decode کرد.
3.کلاینت این توکن را ذخیره کرده و بخاطر ماهیت Stateless بودن پروتکل http بهمراه هر درخواست در Header درخواست توکن jwt را نیز ارسال می کند
4.سرور توکن ارسال بهمراه درخواست دریافت کرده قسمت امضا را با کلیدی که در روی سرور می باشد از رمز خارج می کند و با اطلاعات Headerو payload تطبیق می دهد در صورت درست بودن امضا سرور به درخواست Response می دهد و در غیر اینصورت خطای عدم احراز هویت می دهد
در این سری از اموزش های خودم به اموزش کاربردی ایجاد web api در asp.net core با jwt بهمراه swagger پرداخته می شود.
Authentication ( احراز هویت) : وظیفه اینو داره که هویت کاربر رو بررسی کنه. آیا کاربر وجود داره یا نه؟ آیا مشخصات وارد شده کاربر صحیح هست یا نه؟ اصلا کاربری با این مشخصات وحود داره؟ (کلا کارش یقه کاربر رو گرفتنه.)
Authentication فرآیند تعیین هویت کاربر است.
Authorization (مجوز) : خب حالا که فهمیدیم کاربر وجود داره و مشخصاتی که وارد کرده صحیح بوده، حالا باید بررسی کنیم کاربر عزیزمون چه دسترسی هایی(Permission) داره.(همون Role هایی که براش انتخاب میکنیم و میره توی قسمت های مختلف سایت حال میکنه واسه خودش)
Authorization ?فرآیند تعیین اینکه آیا کاربر به یک منبع دسترسی دارد یا خیر.
در ASP.NET Core، احراز هویت توسط سرویس IAuthenticationService انجام می شود که این سرویس توسط Middleware احراز هویت استفاده می شود.سرویس احراز هویت (authentication service) از کنترل کننده های احراز هویت ثبت شده (registered authentication handlers) برای تکمیل اقدامات مربوط به احراز هویت استفاده می کند.
نمونه هایی از اقدامات مرتبط با احراز هویت ( registered authentication handlers ) به شرح ذیل می باشد:
کنترل کننده های احراز هویت ثبت شده (registered authentication handlers ) و گزینه های پیکربندی آنها "schemes" نامیده می شوند.
برای ثبت Authentication schemes می بایستی وارد Startup و قسمت ConfigureService می شویم و به شرح ذیل عمل می کنیم:
برای مثال ) این کد نحوه ثبت authentication services and handlers برای ookie and JWT bearer authentication schemes به شرح ذیل را نمایش می دهد
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options => Configuration.Bind("JwtSettings", options)) .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options => Configuration.Bind("CookieSettings", options));
پارمتر JwtBearerDefaults.AuthenticationScheme در AddAuthentication نام اسکیمای می باشد که در مواقعی که اسکیمای مشخص درخواست نشده است استفاده می شود
اگر اسکیماهای مختلفی استفاده شود authorization policies (or authorization attributes) می تواند اسکیمای احراز هویت (و یا اسکیماهای) که کاربر برای احزار هویت به ان وابسته است را مشخص کند
درمثال بالا، cookie authentication scheme را می توان با مشخص کردن نام آن ((CookieAuthenticationDefaults.AuthenticationScheme بطور پیش فرض) ،گرچه هنگام فراخوانی AddCookie می توان نام دیگری ارائه داد).
در برخی موارد، با فراخوانی AddAuthentication به طور خودکار با روش های دیگر extension methods انجام می شود. به عنوان مثال، هنگام استفاده از ASP.NET Core Identity اکتنشن متد AddAuthentication به صورت داخلی فراخوانی می شود.
برای استفاده از Authentication middleware می بایستی extension method (اکستنشن متد) UseAuthentication بر روی app's IApplicationBuilder فراخوانی شود.فراخوانی UseAuthentication میان افزاری را که ازregistered authentication schemes ثبت شده قبلی استفاده می کند را ثبت می کند.قبل از هر میان افزاری که به احراز هویت کاربران بستگی دارد، UseAuthentication را فراخوانی کنید. هنگام استفاده از مسیریابی endpoint routing، فراخوانی UseAuthentication باید انجام شود.
حتما برای درک بهتر مطالب مقاله زیر مطالعه شود:
تکنولوژِی Swagger یا OpenAPI یک استاندارد مستقل از زبان است که برای توصیف API های REST است. در واقع Swagger هم به کامپیوتر و هم به انسان این امکان را می دهد که قابلیت های REST API را بدون دسترسی مستقیم به source code درک کنند. اهداف اصلی آن عبارتند از:
پروژه Swagger در سال 2015 به ابتکار OpenAPI اهدا شد و از آن زمان به عنوان OpenAPI نامیده می شود. هر دو نام به جای یکدیگر استفاده می شوند. با این حال “OpenAPI” به مشخصات اشاره دارد و “Swagger” به گروه های open-source و تجاری از SmartBear اشاره می کند که با مشخصات OpenAPI کار می کنند. محصولات متن باز یا open-source بعدی مانند OpenAPIGenerator نیز با وجود عدم انتشار توسط SmartBear تحت نام خانوادگی Swagger قرار می گیرند.
به طور خلاصه می توان گفت:
استاندارد OpenAPI سندی است که قابلیت های API شما را توصیف می کند. این سند بر اساس XML و attribute annotation ها در کنترلرها و مدل ها است. این بخش اصلی جریان OpenAPI است و برای هدایت ابزارهایی مانند SwaggerUI استفاده می شود. به طور پیش فرض، نام آن openapi.json است
رابط کاربری Swagger یک UI مبتنی بر وب ارائه می دهد که اطلاعات مربوط به سرویس را با استفاده از مشخصات OpenAPI ایجاد شده ارائه می دهد. درواقع Swashbuckle و NSwag شامل یک نسخه تعبیه شده از رابط کاربری Swagger هستند، به طوری که می توان آن را با استفاده از یک middleware در برنامه ASP.NET Core شما میزبانی کرد.
مستندسازی API اغلب یک کار خسته کننده و در عین حال ضروری تلقی می شود. با استفاده از OpenAPI یا Swagger که به خوبی با ASP.NET Core ادغام شده است، می توانید این کار را بر اینکار را انجام دهید
ASP.NET Core middleware that enables an application to receive an OpenID Connect bearer token
احراز هویت حامل (Bearer authentication)که احراز هویت توکن (token authentication) نیز نامیده می شود) یک طرح احراز هویت HTTP است که شامل توکن های امنیتی (security tokens)به نام توکن های حامل (bearer tokens)است. نام "احراز هویت حامل" (Bearer authentication) را می توان به عنوان "give access to the bearer of this token" درک کرد. توکن حامل (bearer token) یک رشته رمزی است که معمولاً توسط سرور در پاسخ به درخواست ورود ایجاد می شود. هنگام درخواست برای منابع محافظت شده، مشتری باید این نشانه را در هدر Authorization ارسال کند
تنظیمات متد AddJwtBearer یک چنین مفاهیمی را به همراه دارند:
- تنظیم SaveToken به true، به این معنا است که میتوان به توکن دریافتی از سمت کاربر، توسط متد HttpContext.GetTokenAsync در کنترلرهای برنامه دسترسی یافت.
در قسمت تنظیمات TokenValidationParameters آن:
- کار خواندن فایل appsettings.json برنامه جهت تنظیم صادر کننده و مخاطبین توکن انجام میشود. سپس IssuerSigningKey به یک کلید رمزنگاری متقارن تنظیم خواهد شد. این کلید نیز در تنظیمات برنامه قید میشود.
- تنظیم ValidateIssuerSigningKey به true سبب خواهد شد تا میانافزار اعتبارسنجی، بررسی کند که آیا توکن دریافتی از سمت کاربر توسط برنامهی ما امضاء شدهاست یا خیر؟
- تنظیم ValidateLifetime به معنای بررسی خودکار طول عمر توکن دریافتی از سمت کاربر است. اگر توکن منقضی شده باشد، اعتبارسنجی به صورت خودکار خاتمه خواهد یافت.
- ClockSkew به معنای تنظیم یک تلرانس و حد تحمل مدت زمان منقضی شدن توکن در حالت ValidateLifetime است. در اینجا به صفر تنظیم شدهاست.
سپس به قسمت JwtBearerEvents میرسیم:
- OnAuthenticationFailed زمانی فراخوانی میشود که اعتبارسنجهای تنظیمی فوق، با شکست مواجه شوند. برای مثال طول عمر توکن منقضی شده باشد و یا توسط ما امضاء نشدهباشد. در اینجا میتوان به این خطاها دسترسی یافت و درصورت نیاز آنها را لاگ کرد.
- OnChallenge نیز یک سری دیگر از خطاهای اعتبارسنجی را پیش از ارسال آنها به فراخوان در اختیار ما قرار میدهد.
- Received برای حالتی است که توکن دریافتی، توسط هدر مخصوص Bearer به سمت سرور ارسال نمیشود. عموما هدر ارسالی به سمت سرور یک چنین شکلی را دارد
OnTokenValidated پس از کامل شدن اعتبارسنجی توکن دریافتی از سمت کاربر فراخوانی میشود
امروزه بنای امنیت براساس Claim در نرم افزارهای مبتنی بر وب دارای رویکرد بسیار خوبی است .اما همه درک نمی کنند که claim چیست و چرا باید در نرم افزارهای کاربردی مورد استفاده قرار گیرد. البته مهم تراز معماری و نیازسنجی برای طراحی یک اپلیکیشن، مکانیزم امنیت براساس دسترسی نقش مورد نظر یا براساس امنیت claim یا حتی بدون هیچ احراز هویت و بدون مکانیزم دسترسی است .
با این اوصاف claim یک ویژگی است که برای توصیف کردن یک موضوع استفاده میشود(از دید ما ،شناسایی هویت).
شناسایی تشخیص هویت یک روش متداول است که در برنامه های کاربردی برای بدست آوردن اطلاعات لازم در مورد هویت کاربران داخل سازمان خودمان ، سازمان های دیگر و در اینترنت مورد استفاده قرار میگیرد.
این اصطلاح همانند تفاوت در اختیارات در زمینه دسترسی ها روابط گسترده ای دارد. به عنوان مثال ، سن کاربران در تماشای یک فیلم ترسناک یک نوع سطح دسترسی است. بر اساس claim ، این یک مجوز تشخیص هویت است ، به عنوان مثال : همه افراد دارای سن بالاتر از 16 می توانند (بعضی کار ها را )انجام دهند. اما این امر برای شناسایی هویت ها در مورد ویژگی هایی همانند "سن" وقتی " همه افرادی که میتوانند فیلم ترسناک نگاه کنند باید ..... ساله باشند" آسان نیست.
بنابراین claim یک ویژگی از هویت است که مجوز ها را تعریف میکند ، زمانیکه مجوزهای درستی برای انجام دادن کاری هستند.
Asp.net Identity يك راه جديد براي احراز هويت در پروژه هاي دات نت توسط مايكروسافت مي باشد. آن يك مكانيسم رايج براي به كارگيري در تمام فريم ورك هاي مايكروسافت از جمله web form، mvc، web api و غيره مي باشد. آن متدها و ويژگي هايي را براي مديريت كارربان و نقش ها در دات نت در اختيار ما قرار مي دهد.
Identity در ASP.NET Core ، یک سیستم عضویت است که قابلیت ورود به سیستم را به برنامه های ASP.NET Core اضافه میکند.
کاربران می توانند با اطلاعات ورود به سیستم ذخیره شده در Identity یک حساب ایجاد کنند یا می توانند از یک ارائه دهنده ی( login provider) ورود خارجی استفاده کنند.
فراهم کننده های ورود به سیستم خارجی شامل Facebook، Google، Microsoft Account، و Twitter هستند.
Identity می تواند با استفاده از پایگاه داده ی SQL Server جهت ذخیره ی نام های کاربری، رمز عبورها، و داده های پروفایل پیکربندی شود.
همچنین، انباره ی پایدار دیگری می تواند مورد استفاده قرار بگیرد، برای مثال، Azure Table Storage.
همانطور که داستان سیستم عضویت ASP.NET طی سالیان تغییر و رشد کرده است، تیم ASP.NET نیز آموختههای زیادی از بازخوردهای مشتریان شان بدست آورده اند.
این پیش فرض که کاربران شما توسط یک نام کاربری و کلمه عبور که در اپلیکیشن خودتان هم ثبت شده است به سایت وارد خواهند شد، دیگر معتبر نیست. دنیای وب اجتماعی شده است. کاربران از طریق وب سایتها و شبکههای اجتماعی متعددی با یکدیگر در تماس هستند، خیلی از اوقت بصورت زنده! شبکه هایی مانند Facebook و Twitter.
با در نظر گرفتن تغییراتی که در توسعه اپلیکیشنهای وب بوجود آمده ASP.NET Identity با اهداف زیر متولد شد:
بزار Identity در ASP Core مسئولیت تشخیص هویت و کنترلر دسترسی را به عهده دارد. این ابزار در نسخه های قبل هم وجود داشت اما مانند سایر قسمتها باز نویسی شده است. در اینجا به سه روش اصلی کنترل دسترسی در Idenity Core می پردازیم.
روش Role-Based
در این روش کاربر بر اساس سمتی که دارد به بخش هایی از سایت دسترسی پیدا می کند. مثلا دسترسی به بخش مدیریت سایت فقط برای کاربرهایی با سمت Admin میسر است. در اینجا ما یک جدول برای نگه داری سمت ها داریم و یک جدول هم برای نگه داری رابطه ی بین کاربران با هر سمت. یک کاربر می تواند چندین سمت داشته باشد.
روش Claims-Based
نسخه ی جدید ASP Core تاکید زیادی به استفاده از این روش دارد. در این روش یک کاربر می تواند چند هویت داشته باشد. هر هویت مشخصه های خودش را دارد. دسترسی های یک کاربر بر اساس مشخصه های هر هویت فرق می کند. مثلا شما برای گرفتن وام به بانک مراجعه می کنید و برای شناسایی کارت ملی ارائه می کنید. مشخصات کارت ملی بخشی از مشخصات شما شامل نام و تاریخ تولد را نشان می دهد و یکی از هویت های شما محسوب میشود. حالا اگر بخواهید وام دانشجویی بگیرید باید ثابت کنید دانشجو هستید. در این مرحله کارت دانشجویی ارائه می کنید که شامل نام دانشگاه و شماره ی دانشجویی است. در سیستم Claims-Based انواع مشخصات شما در یک جدول key/value دخیره می شود و بعدا می توانید دسترسی به اکشن ها و کنترلر ها را بر اساس آن محدود کنید.
روش Policy-Based
این شیوه ترکیبی از روشهای قبل است. می توانید برای اجرای هر کدام از اکشنها یک سیاست یا Policy تعریف کنید که می تواند شامل مجموعه از سمت ها و مشخصه های هویتی (Claims) باشد.
علاوه بر اینها چند روش دیگر هم وجود دارد و باید گفت نسخه ی جدید از هر نظر کامل است. به طور کلی پیاده کردن سیستم امنیتی پیچیده است و بهتر است همیشه از Identity استفاده کنید. این سیستم بسیاری از نکات مهم مانند رمز نگاری را به خوبی رعایت کرده است و سطح امنیت سایت را به میزان قابل توجهی بالا می برد.
جدول نقشهای سیستم
کار با ارث بری از نگارش جنریک کلاس IdentityRole شروع میشود. این کلاس پایه، حاوی تعاریف اصلی فیلدهای جدول نقشهای سیستم است که اولین آرگومان جنریک آن، نوع کلید اصلی جدول مرتبط را نیز مشخص میکند و در اینجا به int تنظیم شدهاست. همچنین یک اینترفیس جدید IAuditableEntity را نیز در انتهای این تعریفها مشاهده میکنید. در مورد این اینترفیس و Shadow properties متناظر با آن، در ادامهی بحث با سفارشی سازی DbContext برنامه بیشتر توضیح داده خواهد شد.در اولین بار اجرای برنامه، نقش Admin در این جدول ثبت خواهد شد.
جدول کاربران منتسب به نقشها
کلاس پایهی جدول کاربران منتسب به نقشها، کلاس جنریک IdentityUserRole است که در اینجا با تغییر آرگومان جنریک آن به int، نوع فیلدهای UserId و RoleId آن به int تنظیم میشوند. در کلاس سفارشی سازی شدهی فوق، دو خاصیت اضافهتر User و Role نیز را مشاهده میکنید. مزیت تعریف آنها، دسترسی سادهتر به اطلاعات کاربران و نقشها توسط EF Core است.در اولین بار اجرای برنامه، کاربر شماره 1 یا همان Admin به نقش شماره 1 یا همان Admin، انتساب داده میشود.
جدول جدید IdentityRoleClaim سیستم
در ASP.NET Core Identity، جدول جدیدی به نام RoleClaim نیز اضافه شدهاست. در این سری از آن برای پیاده سازی سطوح دسترسی پویای به صفحات استفاده خواهیم کرد. ابتدا یک سری نقش ثابت در جدول Roles ثبت خواهند شد. سپس تعدادی کاربر به هر نقش نسبت داده میشوند. اکنون میتوان به هر نقش نیز تعدادی Claim را انتساب داد. برای مثال یک Claim سفارشی که شامل ID سفارشی area:controller:action باشد. به این ترتیب و با بررسی سفارشی آن میتوان سطوح دسترسی پویا را نیز پیاده سازی کرد و مزیت آن این است که تمام این Claims به صورت خودکار به کوکی شخص نیز اضافه شده و دسترسی به اطلاعات آن بسیار سریع است و نیازی به مراجعهی به بانک اطلاعاتی را ندارد.
جدول UserClaim سیستم
میتوان به هر کاربر یک سری Claim مخصوص را نیز انتساب داد. برای مثال مسیر عکس ذخیره شدهی او در سرور، چه موردی است و این اطلاعات به صورت خودکار به کوکی او نیز توسط ASP.NET Core Identity اضافه میشوند. البته ما در این سری روش دیگری را برای سفارشی سازی Claims عمومی کاربران بکار خواهیم گرفت (با سفارشی سازی کلاس ApplicationClaimsPrincipalFactory آن).
جداول توکن و لاگینهای کاربران
دراینجا نیز نحوهی سفارشی سازی و تغییر جداول لاگینهای کاربران و توکنهای مرتبط با آنها را مشاهده میکنید. این جداول بیشتر جهت دسترسی به حالتهایی مانند لاگین با حساب کاربری جیمیل مورد استفاده قرار میگیرند و کاربرد پیش فرضی ندارند (اگر از تامین کنندههای لاگین خارجی نمیخواهید استفاده کنید).
جدول کاربران سیستم
در اینجا علاوه بر نحوهی تغییر نوع کلید اصلی جدول کاربران سیستم، نحوهی افزودن خواص اضافهتری مانند نام، تاریخ تولد، مکان، تصویر و غیره را نیز مشاهده میکنید. به علاوه جدولی نیز جهت ثبت سابقهی کلمات عبور هش شدهی کاربران نیز تدارک دیده شدهاست تا کاربران نتوانند از 5 کلمهی عبور اخیر خود (تنظیم NotAllowedPreviouslyUsedPasswords در فایل appsettings.json) استفاده کنند.فیلد IsActive نیز از این جهت اضافه شدهاست تا بجای حذف فیزیکی یک کاربر، بتوان اکانت او را غیرفعال کرد.
یک پروژه از نوع ASP.NET CORE WEB API ایجاد می کنیم
یک اسم برای پروژه انتخاب می کنیم
آخرین نسخه NET رو انتخاب می کنیم
در ابتدای پروژه نسبت به نصب پکیج های به شرح ذیل اقدام می کنیم:
Install-Package Microsoft.EntityFrameworkCore -Version 5.0.12
Install-Package Microsoft.EntityFrameworkCore.Design -Version 5.0.12
Installing NuGet package Microsoft.EntityFrameworkCore.tools 5.0.12
Install-Package Microsoft.EntityFrameworkCore.SqlServer -Version 5.0.12
Install-Package Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore -version 5.0.12
Install-Package Microsoft.AspNetCore.Identity.UI -Version 5.0.12
Install-Package Microsoft.AspNetCore.Authentication.JwtBearer -version 5.0.12
وارد فایل Startup شده و در قسمت ConfigureServices کدهای زیر را اضافه می کنیم
using System.Text; var key = Encoding.ASCII.GetBytes("@#MY_BIG_SECRET_KEY@#");
سپس کد زیر را بعد از کد مذکور به شرح ذیل اضافه می کنیم
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; ; }).AddJwtBearer(options => { options.Events = new JwtBearerEvents { OnTokenValidated = context => { //TODO CODE return Task.CompletedTask; } }; options.RequireHttpsMetadata = false; options.SaveToken = true; options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(key), ValidateIssuer = false, ValidateAudience = false }; });
سپس یک احزار هویت به پروژه اضافه می کنیم
app.UseAuthentication();
یک کنترلر به پروژه به اسم SecurityController از نوع web api empty به پروژه اضافه می کنیم:
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using System.Collections.Generic; namespace SecurityWebApi.Controllers { [Route("api/[controller]")] [ApiController] [Authorize] public class SecurityController : ControllerBase { [HttpGet("getFruits")] [AllowAnonymous] public ActionResult GetFruits() { List<string> mylist = new List<string>() { "apples", "bannanas" }; return Ok(mylist); } [HttpGet("getFruitsAuthenticated")] public ActionResult GetFruitsAuthenticated() { List<string> mylist = new List<string>() { "organic apples", "organic bannanas" }; return Ok(mylist); } } }
پروژه رو اجرا می کنیم :
چون روی کنترلر [Authorize] اعمال شده است لذا چون احرازهویت نشده است پیغام Error: Unauthorized می دهید
یک پوشه Models به پروژه اضافه می کنیم و یک کلاس فایل MyLoginModelType به پروژه اضافه می کنیم:
namespace SecurityWebApi.Models { public class MyLoginModelType { public string Email { get; set; } public string Password { get; set; } } }
در این قسمت متد مربوط به ساختن توکن را ایجاد می کنیم توجه شود چون تا اینجای پروژ هنوز Identity به پروژه اضافه نشده است قسمت بررسی ایمیل و رمز عبور بصورت هارد کد پیاده سازی شده است.
[AllowAnonymous] [HttpPost("getToken")] public async Task<ActionResult> GetToken([FromBody] MyLoginModelType myLoginModelType) { if(myLoginModelType.Email=="javad.jahangiri.niopdc@gamil.com" &&myLoginModelType.Password=="Pa$$w0rd") { var tokenHandler = new JwtSecurityTokenHandler(); var key = Encoding.ASCII.GetBytes("@#MY_BIG_SECRET_KEY@#"); var tokenDescription = new SecurityTokenDescriptor { Subject = new ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.Name, myLoginModelType.Email) } ), Expires = DateTime.UtcNow.AddDays(1), SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key),SecurityAlgorithms.HmacSha256Signature), }; var token = tokenHandler.CreateToken(tokenDescription); var tokenString = tokenHandler.WriteToken(token); return Ok(new { token = tokenString }); } else { return Ok("failed , try again"); } }
در اینجا کاربر با ارسال ایمیل و رمز عبوردر صورت صحیح بودن اطلاعات برای ان توکن ساخته و ارسال می شود
در این قسمت نحوه ارسال توکن در هدر درخواست از طریق نرم افزار postman نمایش داده شده:
در این مرحله اضافه کردن کنترلر Identitiy به پروژه به شرح ذیل می باشد
در ادامه یک DataContext برای ارتباط Identity با دیتابیس sqlserver ایجادمیشود
در این قسمت کلاس سفارشی کاربر برای Identity ایجاد می شود
حال Identity به شرح ذیل به پروژه اضافه می شود:
بعد از اضافه شدن کنترلر Identity جمله اتصال را عوض می کنیم
بعد نسبت به ایجاد مایگریشن و بروزرسانی دیتابیس عمل می کنیم:
Add-Migration createIdentitySchema
Update-Database
همانگونه که مشاهده می کنید دیتابیس به شرح زیر ساخته می شود:
به فایل Startup بر می گردیم :
کدهای زیر را به ان اضافه می کنیم
var userMachine = context.HttpContext.RequestServices.GetRequiredService<UserManager<SecurityWebApiUser>>(); var user = userMachine.GetUserAsync(context.HttpContext.User); if (user == null) context.Fail("UnAuthorized");
مسیر دسترسی به فایل SecurityWebApiUser مسیر SecurityWebApi.Areas.Identity.Data می باشد
حالا به کنترلر Securtiy بر می گردیم و ایتم های زیر را به پروژه اینجکت می کنیم
private readonly SecurityWebApiContext _dbContext; private readonly UserManager<SecurityWebApiUser> _userManager; private readonly SignInManager<SecurityWebApiUser> _signInManager; public SecurityController(SecurityWebApiContext dbContext, UserManager<SecurityWebApiUser> userManager, SignInManager<SecurityWebApiUser> signInManager) { _dbContext = dbContext; _userManager = userManager; _signInManager = signInManager; }
و در نهایت تابع دریافت توکن و ثبت نام را به شرح ذیل در پروژه تغییر می دهیم که بتوانیم با کمک Identityیک کاربر را در دیتابیس ایجاد کنیم از طریق ان لاگین نموده و توکن را دریافت کنیم
[AllowAnonymous] [HttpPost("getToken")] public async Task<ActionResult> GetToken([FromBody] MyLoginModelType myLoginModelType) { var user = _dbContext.Users.FirstOrDefault(x => x.Email == myLoginModelType.Email); if (user != null) { var singInResult = await _signInManager.CheckPasswordSignInAsync(user, myLoginModelType.Password, false); if (singInResult.Succeeded) { var tokenHandler = new JwtSecurityTokenHandler(); var key = Encoding.ASCII.GetBytes("@#MY_BIG_SECRET_KEY@#"); var tokenDescription = new SecurityTokenDescriptor { Subject = new ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.Name, myLoginModelType.Email) } ), Expires = DateTime.UtcNow.AddDays(1), SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature), }; var token = tokenHandler.CreateToken(tokenDescription); var tokenString = tokenHandler.WriteToken(token); return Ok(new { token = tokenString }); } else { return Ok("failed , try again"); } } return Ok("failed , try again"); } [AllowAnonymous] [HttpPost("register")] public async Task<IActionResult> Register([FromBody] MyLoginModelType myLoginModelType) { SecurityWebApiUser securingWebApiDotNetCoreWithIdentity = new SecurityWebApiUser() { Email = myLoginModelType.Email, UserName = myLoginModelType.Email, EmailConfirmed = false, }; var result = await _userManager.CreateAsync(securingWebApiDotNetCoreWithIdentity, myLoginModelType.Password); if (result.Succeeded) { return Ok(new { result = "Register Success" }); } else { StringBuilder sb = new StringBuilder(); foreach (var error in result.Errors) { sb.Append(error.Description); } return Ok(new { Result = $"Register Fail: {sb.ToString()}" }); } }
در تصویر زیر مشاهده می کنیم که یک کاربر در دیتابیس ایجاد می شود
نکته :دقت شود بصورت پیش فرض در Identity در قسمت SignIn گزینه RequireConfirmedAccount فعال می باشد باید انرا غیرفعال کنیم
در نهایت حالا می تواند همانند توضیحات قبلی با این کاربر درخواست یک توکن داده و از طریق این توکن webapi مورد نظر خود را احراز هویت نمایید.
برای دانلود سورس پروژه از گیت هاب بنده استفاده کنید
در دوره های آموزش تضمینی مجتمع فنی ارومیه که به صورت خصوصی و عمومی در دو شیوه حضوری و آنلاین برگزار می شود سرفصل های بسیار متنوع و کاربردی را بصورت پروژه محور آموزش داده می شود تا شخص کارآموز بتواند بلافاصله پس از اتمام این دوره در کمترین زمان ممکن وارد بازار کار شود.
آموزش تخصص ماست با ما حرفه ای شوید
جهت مشاوره با شماره 09149431772 در ارتباط باشید ...