هدایت خودکار کاربر به صفحه لاگین در حین اعمال Ajax ایی
Angular Interceptors
ابتدا مشکل و هدف را بیان میکنیم:
مشکل: کاربر در صفحهای حضور دارد که نیاز به اعتبارسنجی داشته و مدت اعتبار کاربر نیز تمام شده است، ولی هنوز در صفحهای که نباید حضور داشته باشد، حضور دارد و بدتر از آن این است که میتواند درخواستهای بی نتیجهای را نیز ارسال کند.
هدف: کاربر را سریعا به صفحهای که به آن تعلق دارد هدایت کنیم ( یعنی صفحهی ورود به سیستم ).
و حالا از ابتدا پروسه را دنبال میکنیم. یک Controller سمت سرور داریم به این صورت :
[Authorize(Roles = AuthorizeRole.SuperAdministrator)] public partial class HomeController : Controller { [HttpPost] [AngularValidateAntiForgeryToken] public virtual JsonResult GetUserInfo() { var userInfoViewModel = _applicationUserManager.GetUserInfoById(User.Identity.GetUserId()); return Json(userInfoViewModel); } }
یعنی با کدی همانند کد زیر:
$scope.getUserInfo = function() { $http({ method: 'POST', url: 'Home/GetUserInfo', headers: $scope.getHeaders() }). success(function(data, status, headers, config) { $scope.userInfo = data; }). error(function(data, status, headers, config) { }).then(function(res) { }); }
و نتیجهی کدهای بالا به صورت زیر درخواهد آمد :
همانطور که میبینید دادههای اولیه کاربر پس از ورود به سیستم، بدون هیچ مشکلی دریافت میشوند.
نکته : زمانیکه status برابر با 200 هست، یعنی درخواست OK میباشد. ( در پیوست ، لیست تمامی کدها قرار داده شده است )
حالا فرض کنید کاربر در صفحه حضور دارد و به هر دلیلی اعتبار حضور کاربر منقضی شده است و حالا پس از مدتی کاربر درخواستی را به سرور ارسال میکند و میخواهد اطلاعات خودش را مشاهده کند.
درخواست کاربر با همان کدهای اولیه ارسال میشود و خروجی اینبار به صورت زیر در خواهد آمد :
همانطور که میبینید وضعیت اینبار نیز OK میباشد، ولی هیچ دادهای از سرور دریافت نشده است. کاربر قطعا در اینجا دچار سردرگمی میشود. چون هیچ چیزی را مشاهده نمیکند و به هیچ مسیر دیگری نیز هدایت نمیشود و هرکار دیگری نیز انجام دهد، پاسخی مشاهده نمیکند.
راه حل چیست ؟
ابتدا باید برای درخواستهای Ajax ایی اعتبارسنجی را اعمال کنیم. برای این کار باید یک Attribute جدید بسازیم. یعنی به این صورت :
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)] public class MyCustomAuthorize : AuthorizeAttribute { protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { if (filterContext.HttpContext.Request.IsAjaxRequest()) { // یعنی اعتبارسنجی نشده است filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized; filterContext.HttpContext.Response.End(); } base.HandleUnauthorizedRequest(filterContext); } }
توجه : کد کاملتر همراه با توضیحات در بخش پیش نیازها آمده است.
حالا در سمت کلاینت نیز به این صورت عمل میکنیم :
$http({ method: 'POST', url: 'Home/GetUserInfo', headers: $scope.getHeaders() }). success(function(data, status, headers, config) { $scope.userInfo = data; }). error(function(data, status, headers, config) { if (status === 401) { // you are not authorized } }).then(function(res) { });
حالا دیگر متوجه خواهیم شد که کاربر اعتبارسنجی نشده است، یا اعتبار آن منقضی شده است و میتوانیم کاربر را به مسیر "ورود به سیستم" هدایت کنیم.
در console مرورگر نیز خطای زیر رخ میدهد :
POST http://localhost:000000/Administrator/Home/GetUserInfo 401 (Unauthorized)
حالا باید از یک Interceptor استفاده و درخواستهای HTTP خودمان را مدیریت کنیم. برای این منظور ما یک Interceptor جدید را همانند کدهای زیر مینویسیم:
factory('AuthorizedInterceptor', function ($q) { return { response: function(response) { return response || $q.when(response); }, responseError: function(rejection) { if (rejection.status === 401) { // you are not authorized } return $q.reject(rejection); } }; })
همانطور که مشاهده میکنید کدهای خطای درخواست http$ را در Interceptor قرار دادیم. حالا کاربر درخواستی را ارسال میکند و ما با توجه به این Interceptor متوجه خواهیم شد که آیا اعتبار آن منقضی شده است یا خیر و در صورت منقضی شدن، کاربر را به صفحهی ورود هدایت خواهیم کرد. یعنی بدین صورت :
در خروجی بالا میبینید که کاربر، اعتبارسنجی نشده است و آن را به مسیر ورود هدایت خواهیم کرد.
با Interceptor بالا دیگر نیازی نیست برای هر درخواستی این وضعیت را چک کنیم و به صورت خودکار این چک کردن رخ خواهد داد.
پیوست : http_status_codes.rar