هدایت خودکار کاربر به صفحه لاگین در حین اعمال 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
یک روز با ایمیل username@gmail.com ثبت نام میکنند. فردا با ایمیل user.name@gmail.com ثبت نام خواهند کرد. پس فردا با ایمیل us.er.name@gmail.com و به همین ترتیب! امروز با نام «کاربر یک» ثبت نام میکنند. فردا با نام «کاربر یک»! امروز با نام «مجید» ثبت نام میکنند، فردا با نام «مـجـــیـــد»! همچنین علاقهی شدیدی هم به استفاده از ایمیلهای fake دارند (راه حل).
بنابراین نیاز است اطلاعات کاربران را پیش از ثبت نام نرمال سازی کرد. برای مثال نقطههای ایمیلهای جیمیل را حذف کرد؛ یا اگر اجازه دادهاید که در بین کلمات نام کاربری، فاصلهای را وارد کنند، فقط یک فاصله مجاز باشد و یا اگر نامی را ثبت میکنید، به فکر حالتهای کش آمدهی آن مانند «مـجـــــــــیــــــــــد» هم باید بود و آنرا تبدیل به حالت اصلیاش کرد.
نرمال سازی ایمیلهای gmail
تا جایی که اطلاع دارم، حداقل فیس بوک و جیمیل، بکارگیری نقاط را در ایمیلها مجاز میدانند. برای مثال ترکیبهای زیر از دید gmail تنها یک ایمیل محسوب میشوند:
johndoe@gmail.com
john....doe@gmail.com
johndoe+spamsite@gmail.com
راه حل پیشنهادی:
public static string FixGmailDots(string email) { if (string.IsNullOrWhiteSpace(email)) return string.Empty; email = email.ToLowerInvariant().Trim(); var emailParts = email.Split('@'); var name = emailParts[0].Replace(".", string.Empty).Replace("+", string.Empty); var emailDomain = emailParts[1]; string[] domainsAllowedDots = { "gmail.com", "facebook.com" }; var isFromDomainsAllowedDots = domainsAllowedDots.Any(domain => emailDomain.Equals(domain)); return !isFromDomainsAllowedDots ? email : string.Format("{0}@{1}", name, emailDomain); }
این بررسی باید در حین ثبت نام و همچنین ویرایش اطلاعات کاربری جهت نرمال سازی اطلاعات اعمال شود.
اگر سایتهای دیگری هم هستند که بکارگیری نقاط را مجاز میدانند، آرایهی domainsAllowedDots را تکمیل کنید.
نرمال سازی ورود حروف ویژه
نرمال سازی ابتدایی ثبت نام کاربران در سایت جاری به صورت ذیل است:
friendlyName = friendlyName.ApplyCorrectYeKe().RemoveDiacritics().CleanUnderLines().RemovePunctuation(); var trimmedFriendlyName = friendlyName.Trim().Replace(" ", "");
RemoveDiacritics همان حذف اعراب از کلمات است است.
متد پاکسازی underlineهای ویژه یا همان نامهای کش آمده، به صورت زیر است:
public static string CleanUnderLines(string text) { if (string.IsNullOrWhiteSpace(text)) return string.Empty; const char chr1600 = (char)1600; //ـ=1600 const char chr8204 = (char)8204; //=8204 return text.Replace(chr1600.ToString(CultureInfo.InvariantCulture), "") .Replace(chr8204.ToString(CultureInfo.InvariantCulture), ""); }
public static string RemovePunctuation(string text) { return string.IsNullOrWhiteSpace(text) ? string.Empty : new string(text.Where(c => !char.IsPunctuation(c)).ToArray()); }
این موارد، «حداقل»هایی هستند که باید جهت نرمال سازی اطلاعات، در حین ثبت نام اعمال شوند.
مقایسه SQL Server و Oracle
ORDER BY order_by_expression [ COLLATE collation_name ] [ ASC | DESC ] [ ,...n ] [ <offset_fetch> ] <offset_fetch> ::= { OFFSET { integer_constant | offset_row_count_expression } { ROW | ROWS } [ FETCH { FIRST | NEXT } {integer_constant | fetch_row_count_expression } { ROW | ROWS } ONLY ] }
Create Table Testoffset (BusinessEntityID int, FirstName varchar(100) , LastName varchar(100) ); Insert into Testoffset (BusinessEntityID,FirstName,LastName) Values(1,'Ken','Sánchez') ,(2,'Terri','Duffy') ,(3,'Roberto','Tamburello') ,(4,'Rob','Walters') ,(5,'Gail','Erickson') ,(6,'Jossef','Goldberg') ,(7,'Dylan','Miller') ,(8,'Diane','Margheim') ,(9,'Gigi','Matthew') ,(10,'Michael','Raheem')
SELECT BusinessEntityID, FirstName, LastName FROM Testoffset ORDER BY BusinessEntityID OFFSET 3 ROWS FETCH First 3 ROWS only
تولید اتوماتیک مستندات در sql server
مایکروسافت که در نسخه ۲۰۱۶ این نرم افزار با افزودن امکان اجرای برنامههای R و نیز تکمیل امکان اتصال به هدوپ و نیز قابلیت ذخیره و جستجوی دادههای JSON یک گام بلند به سمت ایجاد یک بستر همه منظوره تحلیل داده برداشته بود، با امکانات جدیدی که در نسخه ۲۰۱۷ به مجموعه SQL Server اضافه کرده است، آنرا به یک گزینه مناسب و جامع برای کارهای تراکنش محور و نیز تحلیلی تبدیل کرده است