احراز هویت مبتنی بر Token توسط Web Api

Token

در این مقاله قصد داریم چگونگی ایمن سازی ASP.NET Web API  با استفاده از روش Token Based Authentication (تایید هویت مبتنی بر Token ها) را نشان دهیم.

ASP.NET Web API فریم ورکی است که ایجاد سرویس های HTTP  را بسیار آسان کرده است.

سرویس های مبتنی بر HTTP کلاینت های زیادی را در بر می گیرد: مرورگرها، موبایل ها و کامپیوترهای شخصی. امروزه Web API adoption به سرعت در حال گسترش است.

در این شرایط، ضرورت توجه به مسائل مربوطه به امنیت به چشم می خورد؛ پس تمامی کلاینت هایی که به نحوی با داده های مربوط به سرویس های Web API در ارتباط هستند باید نسبت به تهدیدات امنیتی، تجهیز شوند.

رایج ترین روش برای ایمن سازی منابع سروری، تایید هویت کاربران در WEB API ، استفاده از Token های نشانه گذاری شده است؛ که شامل داده های کافی برای شناسایی یک کاربر خاص است. این روش نامیده می شود البته به دلایل زیر:

اتصال سست(Loose Coupling): اپلیکیشنی که در سمت کلاینت است، به یک بخش مختص برای احراز هویت متصل نیست.

Token تولید شده، اعتبارسنجی می شود و توسط سرور، احراز هویت انجام می شود.

سازگاری با تلفن های همراه(Mobile Friendly): در پلتفرم های پایه مثل iOS،Android، Windows 8 ، مدیریت کوکی ها کار آسانی نیست. با استفاده از روش مبتنی بر Token ،مدیریت کوکی ها بسیار آسان می شود.

Token

احراز هویت مبتنی بر توکن ها چگونه کار می کند؟

در این روش ابتدا برنامه سرویس گیرنده درخواست احراز هویتی را با اعتبار مناسبی برای سرور می فرستد.

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

این توکن شامل اطلاعات کافی برای شناسایی یک کاربر خاص و همچنین تاریخ انقضااین اتصال، می دهد. سپس برنامه سرویس گیرنده برای دسترسی به منابع، در درخواست های بعدی، از این توکن استفاده می کند تا زمانی که این توکن معتبر باشد.

مراحل زیر را مرحله به مرحله انجام دهید تا قسمت اول احراز هویت مبتنی بر توکن ها با استفاده از ASP.NET Web API 2  را پیاده سازی کنیم.

در این مقاله از نرم افزار Visual Studio ۲۰۱۳ استفاده می کنیم.

قدم ۱: یک پروژه جدید ایجاد کنید.

به ترتیب به قسمت های menu ، create، projet رفته و گزینه  “asp.net web application”  را انتخاب کنید سپس نام برنامه را وارد کنید در قسمت بعد، مکان مربوط به پروژه را تعیین کنید و در نهایت روی دکمه add  کلیک کنید.

حالا پنجره جدیدی برای انتخاب template  باز می شود. گزینه empty template را انتخاب می کنیم سپس چک باکس را MVC & Web API را فعال می کنیم (از بخش Add folder and core references for ) و در نهایت روی دکمه Ok  کلیک می کنیم.

قدم ۲: از بسته NuGet ، ارجاع های مورد نیاز را به برنامه اضافه کنید.

برای پیاد سازی یک روش مبتنی بر توکن در WEB API ، باید ارجاع های زیر از بسته NuGet نصب شوند.

  1. Microsoft.Owin.Host.SystemWeb
  2. Microsoft.Owin.Security.OAuth .
  3. Microsoft.Owin.Cors

برای اضافه کردن این منابع از  NuGet، به قسمت Solution Explorer می رویم و روی  References راست کلیک می کنیم سپس روی Manage NuGet packages  کلیک می کنیم در قسمت بعد، Microsoft.Owin.Host.SystemWeb,  Microsoft.Owin.Security.OAuth & Microsoft.Owin.Cors را سرچ کرده و نصبشان می کنیم.

قدم ۳: یک کلاس، برای اعتبار سنجی درخواست های فرستاده شده از طرف کاربر، با استفاده از توکن ها ایجاد کنید.

حالا به برنامه کلاسی ،برای بررسی اعتبار درخواست تایید کاربر و ایجاد توکن، اضافه می کنیم.

برای اضافه کردن کلاس به قسمت solution explorer می رویم روی نام برنامه مان راست کلیک می کنیم گزینه add  را انتخاب می کنیم سپس New Item… و اینجا کلاس را انتخاب می کنیم. نامی برای کلاس وارد می کنیم و روی دکمه Add  کلیک می کنیم.

در این کلاس برای بازنویسی دو متد  “ValidateClientAuthentication” و “GrantResourceOwnerCredentials” ، از کلاس “OAuthAuthorizationServerProvider” ارث بری می کنیم.

متد “ValidateClientAuthentication” برای بررسی صحت برنامه سرویس گیرنده ( برای ساده تر شدن کار، در ادامه روی متد “ValidateClientAuthentication”  تمرکز بیشتری می کنیم) و در متد “GrantResourceOwnerCredentials”   کاربران را احراز هویت می کنیم و اگر تایید شد یک توکن علامت دار ایجاد می کنیم تا کاربر بتواند با آن به منابع سرور دسترسی پیدا کند.

MyAuthorizationServerProvider.cs


using Microsoft.Owin.Security.OAuth;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using System.Web;
 
namespace webApiTokenAuthentication
{
    public class MyAuthorizationServerProvider : OAuthAuthorizationServerProvider
    {
        public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
        {
            context.Validated(); // 
        }
 
        public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
        {
            var identity = new ClaimsIdentity(context.Options.AuthenticationType);
            if (context.UserName == "admin" context.Password == "admin")
            {
                identity.AddClaim(new Claim(ClaimTypes.Role, "admin"));
                identity.AddClaim(new Claim("username", "admin"));
                identity.AddClaim(new Claim(ClaimTypes.Name, "Sourav Mondal"));
                context.Validated(identity);
            }
            else if (context.UserName == "user" context.Password == "user")
            {
                identity.AddClaim(new Claim(ClaimTypes.Role, "user"));
                identity.AddClaim(new Claim("username", "user"));
                identity.AddClaim(new Claim(ClaimTypes.Name, "Suresh Sha"));
                context.Validated(identity);
            }
            else
            {
                context.SetError("invalid_grant", "Provided username and password is incorrect");
                return;
            }
        }
    }
}

در خطوط ۱۸ تا ۴۰ از داده های استاتیکی برای تائید اعتبار کاربران استفاده کردیم. در قسمت بعدی این آموزش، وقتی برنامه سرویس گیرنده (در in AngularJS) با روش احراز هویت مبتنی بر توکن پیاده سازی شود برای اعتبار سنجی از پایگاه داده مان استفاده می کنیم.

قدم ۴: Owin Start Up classرا اضافه کنید.

حالا در قسمتی که OAuth Authorization Server را پیکربندی می کنیم ، OWIN Startup  class را اضافه می کنیم.

به قسمت  Solution Explorer می رویم و روی Project Name راست کلیک می کنیم و به Add  رفته و سپس به قسمت New Item ، حالا OWIN Startup class را انتخاب می کنیم و در نهایت نام کلاس را انتخاب می کنیم و Add را انتخاب می کنیم.

Startup.cs


using System;
using System.Threading.Tasks;
using Microsoft.Owin;
using Owin;
using Microsoft.Owin.Security.OAuth;
using System.Web.Http;
 
[assembly: OwinStartup(typeof(webApiTokenAuthentication.Startup))]
 
namespace webApiTokenAuthentication
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=316888
            //enable cors origin requests
            app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
 
            var myProvider = new MyAuthorizationServerProvider();
            OAuthAuthorizationServerOptions options = new OAuthAuthorizationServerOptions
            {
                AllowInsecureHttp = true,
                TokenEndpointPath = new PathString("/token"),
                AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
                Provider = myProvider
            };
            app.UseOAuthAuthorizationServer(options);
            app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
 
 
            HttpConfiguration config = new HttpConfiguration();
            WebApiConfig.Register(config);
        }
    }
}

قدم ۵: برای بازنویسی نحوه انتخاب متغیرها یک کلاس دیگر را اضافه می کنیم.

هنگامی که در حال ایجاد HTTP REST API هستیم ، باید از کدهای appropriate HTTP response برای نمایش وضعیت پاسخ استفاده کنیم.

بهتر است بین ۴۰۱ تا ۴۰۳ کد وضعیت برای authentication/authorization استفاده کنیم.

۴۰۱ (Unauthorized): این کد نشان می دهد تقاضای فعلی اجرایی نمی شود زیرا اعتبارش برای دسترسی به منبع مورد نظر مورد تائید نیست.

۴۰۳(Forbidden): وقتی یک کاربر هویتش احراز می شود ولی اجازه تقاضا و دسترسی به منابع را ندارد.

متاسفانه، متغیرهای ASP.NET MVC/Web API Authorize به این صورت عمل نمی کنند و همیشه ۴۰۱ را نشان می دهند پس در Web API applicationمان، کلاسی برای بازنویسی این رفتار ایجاد می کنم.

اینجا به ۴۰۳ بر می گردیم وقتی که کاربر هویتش احراز شده ولی نمی تواند درخواست دسترسی به منابع را بکند.

AuthorizeAttribute.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
 
namespace webApiTokenAuthentication
{
    public class AuthorizeAttribute : System.Web.Http.AuthorizeAttribute
    {
        protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
        {
            if (!HttpContext.Current.User.Identity.IsAuthenticated)
            {
                base.HandleUnauthorizedRequest(actionContext);
            }
            else
            {
                actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);
            }
        }
    }
}


قدم ۶: حالا یک WEB API Controller ایجاد می کنیم.

در کنترلر WEB API Controller برخی اقدامات اضافه می شود پس می توانیم بررسی کنیم که آیا احراز هویت با استفاده از توکن خوب کار می کند یا خیر.

به قسمت Solution Explorer می رویم  سپس روی پوشه کنترلرها راست کلیک می کنیم به Add  رفته و سپس به قسمت Controller می رویم WEB API 2 Controller – Empty را انتخاب می کنیم روی دکمه add  کلیک می کنیم  و نام کنترلر را وارد می کنیم(در مثال من نام DataController.cs است.) و در آخر Add را انتخاب می کنیم.

قدم ۷: برای گرفتن اطلاعات از سرور برای تمامی کاربران ناشناس یک اضافه می کنیم.

این را برای تمامی کاربران ناشناس اعمال می کنم. هرنوع درخواستی ( چه تایید شده چه رد شده) می تواند به این دسترسی پیدا کند.


[AllowAnonymous]
[HttpGet]
[Route("api/data/forall")]
public IHttpActionResult Get()
{
    return Ok("Now server time is: " + DateTime.Now.ToString());
}

قدم ۸: برای گرفتن اطلاعات از سرور برای تمامی کاربرانی که هویتشان احراز شده،یک action اضافه می کنیم.

این action را برای تمامی کاربرانی که هویتشان احراز شده اعمال می کنم. ( چه کاربر ادمین باشد یا کاربر معمولی)


[Authorize]
[HttpGet]
[Route("api/data/authenticate")]
public IHttpActionResult GetForAuthenticate()
{
    var identity = (ClaimsIdentity)User.Identity;
    return Ok("Hello " + identity.Name);
}

قدم ۹: برای گرفتن اطلاعات ادمین از سرور،  یکaction  دیگر  اضافه می کنیم.

این فقط مختص ادمین است.


[Authorize(Roles="admin")]
[HttpGet]
[Authorize(Roles="admin")]
[HttpGet]
[Route("api/data/authorize")]
public IHttpActionResult GetForAdmin()
{
    var identity = (ClaimsIdentity)User.Identity;
    var roles = identity.Claims
                .Where(c = c.Type == ClaimTypes.Role)
                .Select(c = c.Value);
    return Ok("Hello " + identity.Name + " Role: " + string.Join(",", roles.ToList()));
}

قدم ۱۰:  برنامه را اجرا کنید.

پیکربندی WEB APIمان آماده است حالا برنامه را با POSTMAN  تست می کنیم و سپس در قسمت بعدی نحوه ایجاد یک برنامه سمت کلاینت ( AngularJS application) و یک برنامه سمت سرور را نشان خواهم داد تا احراز هویت براساس توکن ها را امتحان کنیم.

Postman  افزونه ای برای مرورگر Chrome است که از آن به عنوان یک برنامه کلاینتی استفاده می شود تا درخواست و پاسخ بین کلاینت و سرور را تست کند.

در این قسمت شما نقش برنامه را نیز ایفا می کنید.

پس پیغام خطایی به صورت “The resource cannot be found” دریافت می کنید زیرا در root urlمان هیچ چیزی نداریم اما جای نگرانی نیست در ادامه این کار را انجام خواهیم داد.

ابتدا POSTMAN مان را برای  تست  Web APIمان باز می کنیم  سپس از لینک های زیر استفاده می کنیم…

تست اول:

GET  را انتخاب کنید(تصویر section 1) سپس http://localhost:/api/data/forall  را به عنوان url  را وارد کنید (تصویر section 2) و روی دکمه send  کلیک کنید.

حالا  وضعیت ۲۰۰ OK را دریافت می کنیم(تصویر section 3 ) و نتیجه در تصویر section 4نمایش داده شده است. و این به این معنی است که وقتی درخواست ناشناسی آمده اولین به درستی کار کرده است.

 Identity چیست ؟

اما الان می خواهیم به دومین action  دسترسی پیدا کنیم((GetForAuthenticate with url : http://localhost:/api/data/authenticate)) سپس ۴۰۱ را دریافت کنیم زیرا تاکنون درخواست احراز هویت نشده است. برای سومین action  نتیجه ای مشابه رخ می دهد.

بنابراین برای دسترسی به دومین و سومین action  به چه چیزی احتیاج داریم؟ در ابتدا به Tokenدسترسی که در سرور است احتیاج داریم و سپس می توانیم به وسیله این Tokenدسترسی به دومین و سومین action  دسترسی پیدا کنیم.

تست ۲:دریافت توکن دسترسی.

POST را انتخاب کنید(در section 1)، http://localhost:/token را وارد کنید (در section 2) و سپس روی body کلیک کنید(در section 3) و x-www-form-urlencoded  را انتخاب کنید و ۳ پارامتر وارد کنید، اولین پارامتر.نام کاربری(value : user) دومین پارامتر رمز عبور(value : user) وسومین پارامتر grant_type value: password.

حالا روی دکمه send  کلیک می کنیم و ۲۰۰ OK را دریافت می کنیم (section 4 را نگاه کنید) و توکن دسترسی.( section 5 را مشاهده کنید)

 Owin Security

حالا می توانیم به وسیله توکن دسترسی به http://localhost:/api/data/authenticate

دسترسی پیدا کنیم.

تست سوم:دسترسی به منابع نامحدود به وسیله

دسترسی

منظور از section ها تصویر زیر است.

GET را انتخاب کنید(در section 1)، http://localhost:/api/data/authenticate را وارد کنید (در section 2) و سپس روی Headers کلیک کنید(در section 3) و یک پارامتر وارد کنید(Authorization (value : Bearer))، و سپس روی دکمه send  کلیک می کنیم و  ۲۰۰ OK را دریافت می کنیم (section 4 را نگاه کنید) و نتیجه هم در section 5 قابل مشاهده است.

Identity

به روش مشابه می توانیم به سومین action دسترسی پیداکنیم(با استفاده از username : admin and password: admin) اما باید Token را دریافت کنیم زیرا سومین action فقط برای ادمین قابل دسترسی است.

 

  • پسورد: www.mspsoft.com
مسعود شریفی پور

از سال 88 که با برنامه نویسی آشنا شدم خیلی علاقه مند بودم یک بستر آموزشی بسازم در فضای وب و به انتشار آموزش های در این زمینه بپردازم.حالا یک تیم داریم و با قدرت رو به جلو حرکت میکنیم.

نوشته‌های مرتبط

دیدگاه‌ها

*
*

این سایت از اکیسمت برای کاهش هرزنامه استفاده می کند. بیاموزید که چگونه اطلاعات دیدگاه های شما پردازش می‌شوند.

    وحید پاسخ

    سلام و عرض ادب .ممنون از مطالب مفیدتون.این مورد تو دستگاه من کار میکنه ولی وقتی روی سرور میزارمش پیغام زیرو میده
    StatusCode: 500, ReasonPhrase: 'Internal Server Error'
    ممنون میشم راهنمایی بفرمایین

      پویا قربانی پاسخ

      ارور 500 مربوط به سرور است ، باید خط به خط دیباگ کنید.IIS و نسخه فریم ورک را نیز بررسی کنید.

    امین پاسخ

    خیلی ممنون
    اجرتون با خدا

    سید علی حسینی پاسخ

    خدا خیر و برکت به شما بدهد خیلی عالی توضیح داده بودین

    سعید پاسخ

    سلام
    اگر بخواییم توکنی که برمیگردونه به صورت encoding base64 باشه باید چکار کنیم ؟

    حمید پاسخ

    سلام
    من تمام مراحل را مانند شما انجام دادم و برای api/data/forall هم به درستی جواب می دهد. اما برای http://localhost:56851/token ارور زیر را می دهد. IIS 10.0 Detailed Error - 404.0 - Not Found
    لطفاً راهنمایی بفرمایید.

    حمید پاسخ

    سلام
    من تمام مراحل را مانند شما انجام دادم و برای api/data/forall هم به درستی جواب می دهد. اما برای http://localhost:56851/token ارور زیر را می دهد. IIS 10.0 Detailed Error – 404.0 – Not Found
    لطفاً راهنمایی بفرمایید.

    مصطفی پاسخ

    سلام
    ممنونم عالی بود
    فقط من لزوم grant_type رو نفهمیدم و چرا password قرارمیدیم قدارشو آیا قابل کاستومایز هستش؟

    حمید پاسخ

    سلام در قسمتی از این اموزش گفته شده است که:
    "در خطوط ۱۸ تا ۴۰ از داده های استاتیکی برای تائید اعتبار کاربران استفاده کردیم. در قسمت بعدی این آموزش، وقتی برنامه سرویس گیرنده (در in AngularJS) با روش احراز هویت مبتنی بر توکن پیاده سازی شود برای اعتبار سنجی از پایگاه داده مان استفاده می کنیم."
    این اموزش را نمی توانم پیدا کنم.
    لطفاً لینک قسمت بعدی این اموزش را قرار دهید.
    سپاس فراوان

    میلاد پاسخ

    سلام
    روت http://localhost:/token کجا مشخ شده؟ برای من این url کار نمی کنه

    امین پاسخ

    عالی نود.ساده و مفید

    farhadbm پاسخ

    سلام و وقت بخیر و خسته نباشید
    بابت مطلب ، واقعا سپاس گذارم.
    من از این روش در پروژه استفاده کردم تنها مشکلی که باهاش خوردم منقضی شدن سریع توکن هست. آیا برای این کار روشی پیشنهاد میکنید؟؟
    من مقدار AccessTokenExpireTimeSpan این رو هم تا یک ماه بردم ولی فرقی نکرده.
    ممنون میشم کمکم کنید خیلی گیرم.
    با تشکر فراوان

      مسعود شریفی پور پاسخ

      روی لوکال هم چنین مشکلی دارید ؟ یا روی سرور با این مشکل رو به رو هستید ؟

    farhadbm پاسخ

    نه روی سرور با همچین مشگلی مواجهم و machineKey هم داخل وب کانفیگ ست کردم.

      مسعود شریفی پور پاسخ

      پیشنهاد میکنم یه تیکت به سرور بزنید در این خصوص ، که زمان expiry شدند session را افزایش بدن ، احتمالا محدودیت دارید.

    hanan پاسخ

    باسلام
    ممنونم از مطلبتون خیلی مفید و کاربردی بود

    بابک پاسخ

    عالی بود تنها مطلب و اول مطلب بود که بسیار شفاف و بدون ایراد گام به گام ایجاد و اجرا کردم در مورد jwt. بینهایت سپاسگذارم./ اگر بتونید قسمت refresh token هم با یک کد کلاینت jquery به ادامه این مطلب اضافه بفرمائید ایده آل ترین آموزش در مورد token ها خواهد بود که توسعه دهنده ها رو سردرگم نکرده و راهنمای عالی تری خواهد بود. باز سپاسگذارم.

      زهره سلطانیان پاسخ

      با سلام
      ممنون از شما. سعی میکنیم در مقالات دیگر این موضوع را پیگیری کنیم.