نظرات مطالب
ASP.NET MVC #18
البته به طور دستی تونستم این مورد رو موقتا برطرف کنم
 FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
                      1,                                     // ticket version
                      admin.UserName,                              // authenticated username
                      DateTime.Now,                          // issueDate
                      DateTime.Now.AddMinutes(30),           // expiryDate
                      true,                          // true to persist across browser sessions
                      "",                              // can be used to store additional user data
                      FormsAuthentication.FormsCookiePath);  // the path for the cookie

                    // Encrypt the ticket using the machine key
                    var encryptedTicket = FormsAuthentication.Encrypt(ticket);

                    // Add the cookie to the request to save it
                    var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket) {HttpOnly = true};
                    Response.Cookies.Add(cookie);
نظرات مطالب
به اشتراک گذاری داده ها بین کنترلرها در AngularJs
بله. اگر متدی را به کنترلر 2 اضافه کنید و سپس یک تگ لینک در view برای فراخوانی این متد، به صورت زیر :
sampleApp.controller('controller2', function ($scope, BookData) {
    $scope.books = BookData;
    $scope.change = function(){
         BookData[0].name = 'change this book';
    }
});

 و view :
<div ng-controller="controller2">
        <p>Data from controller2</p>
        <table>
            <tr ng-repeat="book in books">
                <td>
                    {{book.code}}
                </td>
                <td>
                    {{book.name}}
                </td>
            </tr>
        </table>
<a href="javascript:void(0)" ng-click="change();" >Click here to change book1</a>
    </div>
میبینید که در کنترلر شماره 1 هم تغییر میکند.
مطالب
iTextSharp و نمایش صحیح تاریخ در متنی راست به چپ

خروجی PDF زیر را در نظر بگیرید:

مشکلی را در آن مشاهده می‌کنید؟ اصل آن یا صحیح آن باید به شکل زیر باشد:


و این وارونه نمایش دادن‌ها، دقیقا مشکلی است که حین کار با iTextSharp برای نمایش متنی مثلا به همراه یک تاریخ شمسی وجود دارد. البته این مشکل هم اساسا به خود استاندارد یونیکد برمی‌گرد که یک سری کاراکتر را «کاراکتر ضعیف» معرفی کرده؛ برای مثال کاراکتر اسلش بکار رفته در یک تاریخ هم از این دست است. بنابراین PDF تولیدی توسط iTextSharp از دید استاندارد یونیکد مشکلی ندارد، زیرا یک «نویسه ضعیف» مثل اسلش نمی‌تواند جهت را تغییر دهد؛ مگر اینکه از یک «نویسه قوی» برای دستکاری آن استفاده شود. برای مثال این نویسه‌ها قوی هستند:

U+202A:   LEFT-TO-RIGHT EMBEDDING (LRE) 
U+202B:   RIGHT-TO-LEFT EMBEDDING (RLE)
U+202D:   LEFT-TO-RIGHT OVERRIDE (LRO)
U+202E:   RIGHT-TO-LEFT OVERRIDE (RLO)
U+202C:   POP DIRECTIONAL FORMATTING (PDF)

برای رسیدن به تصویر صحیح نمایش داده شده در بالا، متد FixWeakCharacters زیر را تهیه کرده‌ام که حداقل با iTextSharp جواب می‌ده:

using System;
using System.Diagnostics;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;

namespace RleTests
{
class Program
{
const char RightToLeftEmbedding = (char)0x202B;
const char PopDirectionalFormatting = (char)0x202C;

static string FixWeakCharacters(string data)
{
if (string.IsNullOrWhiteSpace(data)) return string.Empty;
var weakCharacters = new[] { @"\", "/", "+", "-", "=", ";", "$" };
foreach (var weakCharacter in weakCharacters)
{
data = data.Replace(weakCharacter, RightToLeftEmbedding + weakCharacter + PopDirectionalFormatting);
}
return data;
}

static void Main(string[] args)
{
using (var pdfDoc = new Document(PageSize.A4))
{
PdfWriter.GetInstance(pdfDoc, new FileStream("Test.pdf", FileMode.Create));
pdfDoc.Open();

FontFactory.Register("c:\\windows\\fonts\\Arial.ttf");
Font tahoma = FontFactory.GetFont("Arial", BaseFont.IDENTITY_H);

var table1 = new PdfPTable(1);
table1.WidthPercentage = 100;

var pdfCell = new PdfPCell
{
RunDirection = PdfWriter.RUN_DIRECTION_RTL,
Border = 0,
Phrase = new Phrase(FixWeakCharacters(
"تاریخ: " + "1390/11/18" + Environment.NewLine +
"شماره پروژه: " + "1/2/3/4/56" + Environment.NewLine +
"اسلش: " + " 12/A/13 " + Environment.NewLine +
"بک اسلش: " + " 12\\13\\14 " + Environment.NewLine +
"مساوی و جمع: " + " 2+3=5 " + Environment.NewLine +
"سمی کولون: " + " 2=1+1; " + Environment.NewLine +
"دلار: " + "12$" + Environment.NewLine +
"کاما: " + "12,34,67" + Environment.NewLine +
"نقطه: " + "12.34" + Environment.NewLine +
"پرانتز: " + "متن (ساده)"
),
tahoma)
};

table1.AddCell(pdfCell);
pdfDoc.Add(table1);

}

Process.Start("Test.pdf");
}
}
}

از این نوع مشکلات حین کار با HTML هم هست؛ وارونه نمایش داده شدن تاریخ فارسی در بین یک متن راست به چپ. البته در آنجا راه حل زیر هم توصیه شده (بدون نیاز به دستکاری نویسه‌ها):

<span dir="ltr" style="display:inline">1390/11/19</span>

مطالب
iTextSharp و نمایش صحیح تاریخ در متنی راست به چپ

خروجی PDF زیر را در نظر بگیرید:

مشکلی را در آن مشاهده می‌کنید؟ اصل آن یا صحیح آن باید به شکل زیر باشد:


و این وارونه نمایش دادن‌ها، دقیقا مشکلی است که حین کار با iTextSharp برای نمایش متنی مثلا به همراه یک تاریخ شمسی وجود دارد. البته این مشکل هم اساسا به خود استاندارد یونیکد برمی‌گردد که یک سری کاراکتر را «کاراکتر ضعیف» معرفی کرده؛ برای مثال کاراکتر اسلش بکار رفته در یک تاریخ هم از این دست است. بنابراین PDF تولیدی توسط iTextSharp از دید استاندارد یونیکد مشکلی ندارد، زیرا یک «نویسه ضعیف» مثل اسلش نمی‌تواند جهت را تغییر دهد؛ مگر اینکه از یک «نویسه قوی» برای دستکاری آن استفاده شود. برای مثال این نویسه‌ها قوی هستند:

U+202A:   LEFT-TO-RIGHT EMBEDDING (LRE) 
U+202B:   RIGHT-TO-LEFT EMBEDDING (RLE)
U+202D:   LEFT-TO-RIGHT OVERRIDE (LRO)
U+202E:   RIGHT-TO-LEFT OVERRIDE (RLO)
U+202C:   POP DIRECTIONAL FORMATTING (PDF)

برای رسیدن به تصویر صحیح نمایش داده شده در بالا، متد FixWeakCharacters زیر را تهیه کرده‌ام که حداقل با iTextSharp جواب می‌ده:

using System;
using System.Diagnostics;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;

namespace RleTests
{
class Program
{
const char RightToLeftEmbedding = (char)0x202B;
const char PopDirectionalFormatting = (char)0x202C;

static string FixWeakCharacters(string data)
{
if (string.IsNullOrWhiteSpace(data)) return string.Empty;
var weakCharacters = new[] { @"\", "/", "+", "-", "=", ";", "$" };
foreach (var weakCharacter in weakCharacters)
{
data = data.Replace(weakCharacter, RightToLeftEmbedding + weakCharacter + PopDirectionalFormatting);
}
return data;
}

static void Main(string[] args)
{
using (var pdfDoc = new Document(PageSize.A4))
{
PdfWriter.GetInstance(pdfDoc, new FileStream("Test.pdf", FileMode.Create));
pdfDoc.Open();

FontFactory.Register("c:\\windows\\fonts\\Arial.ttf");
Font tahoma = FontFactory.GetFont("Arial", BaseFont.IDENTITY_H);

var table1 = new PdfPTable(1);
table1.WidthPercentage = 100;

var pdfCell = new PdfPCell
{
RunDirection = PdfWriter.RUN_DIRECTION_RTL,
Border = 0,
Phrase = new Phrase(FixWeakCharacters(
"تاریخ: " + "1390/11/18" + Environment.NewLine +
"شماره پروژه: " + "1/2/3/4/56" + Environment.NewLine +
"اسلش: " + " 12/A/13 " + Environment.NewLine +
"بک اسلش: " + " 12\\13\\14 " + Environment.NewLine +
"مساوی و جمع: " + " 2+3=5 " + Environment.NewLine +
"سمی کولون: " + " 2=1+1; " + Environment.NewLine +
"دلار: " + "12$" + Environment.NewLine +
"کاما: " + "12,34,67" + Environment.NewLine +
"نقطه: " + "12.34" + Environment.NewLine +
"پرانتز: " + "متن (ساده)"
),
tahoma)
};

table1.AddCell(pdfCell);
pdfDoc.Add(table1);

}

Process.Start("Test.pdf");
}
}
}

از این نوع مشکلات حین کار با HTML هم هست؛ وارونه نمایش داده شدن تاریخ فارسی در بین یک متن راست به چپ. البته در آنجا راه حل زیر هم توصیه شده (بدون نیاز به دستکاری نویسه‌ها):

<span dir="ltr" style="display:inline">1390/11/19</span>

مطالب
ایجاد ویژگی‌های اعتبارسنجی سفارشی در ASP.NET Core 3.1 به همراه اعتبارسنجی سمت کلاینت آن‌ها
اگر بخواهیم یک Attribute سفارشی را برای اعتبارسنجی ایجاد کنیم، معمولا یک کلاس را ایجاد کرده و از ValidationAttribute ارث بری می‌کنیم و سپس متد IsValid آن‌را override میکنیم؛ با توجه به نیازی که به آن Attribute داریم. به عنوان مثال در ادامه یک Attribute را ایجاد کرده‌ایم که عمل مقایسه‌ی دو خاصیت را انجام میدهد و اگر مقدار خاصیتی که ویژگی LowerThan بر روی آن قرار دارد، از مقدار خاصیت دیگری که باید با آن مقایسه شود، کمتر نباشد، یک خطا را به ModelState اضافه میکنیم:
public class LowerThanAttribute : ValidationAttribute
{
    public LowerThanAttribute(string dependentPropertyName)
    {
        DependentPropertyName = dependentPropertyName;
    }

    public string DependentPropertyName { get; set; }
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        int? currentPropertyValue = value as int?;
        currentPropertyValue ??= 0;
        var typeInfo = validationContext.ObjectInstance.GetType();
        var dependentPropertyValue = Convert.ToInt32(typeInfo.GetProperty(DependentPropertyName)
                                        .GetValue(validationContext.ObjectInstance, null));

        var displayDependentProperyName = typeInfo.GetProperty(DependentPropertyName)
                                        .GetCustomAttributes(typeof(DisplayAttribute), false)
                                        .Cast<DisplayAttribute>()
                                        .FirstOrDefault()?.Name;

        if (!(currentPropertyValue.Value < dependentPropertyValue))
        {
            return new ValidationResult("مقدار {0} باید کمتر باشد از " + displayDependentProperyName);
        }
        return ValidationResult.Success;
    }
}
ابتدا مقدار خاصیت مورد نظر را که میخواهیم با آن مقایسه شود، با استفاده از رفلکشن گرفته‌ایم و آن را در متغییر dependentPropertyValue ذخیره میکنیم. در ادامه مقدار Name را با استفاده از رفلکشن از DisplayAttribute میخوانیم و سپس عمل مقایسه را انجام میدهیم که اگر مقدار خاصیتی که ویژگی LowerThan بر روی آن قرار دارد، از مقدار خاصیت مورد نظر که مقدار آن را با استفاده از رفلکشن خوانده‌ایم، کمتر نباشد، یک خطا را به ModelState اضافه میکنیم.

اما یک مشکل! این عمل فقط در سمت سرور بررسی میشود و هنگامیکه ModelState.IsValid را در اکشن متد فراخوانی میکنیم، عمل اعتبارسنجی انجام میشود. یعنی همه‌ی داده‌ها به سمت سرور ارسال میشوند و اگر خطایی در ModelState وجود داشته باشد، کاربر مجددا باید داده‌ها را ارسال کند.

اما میتوان با استفاده از اینترفیس IClientModelValidator، عمل اعتبارسنجی را برای این ویژگی در سمت کلاینت انجام داد. برای انجام این کار ابتدا باید از اینترفیس IClientModelValidator ارث بری کنیم و متد AddValidation آن را پیاده سازی کنیم.
public class LowerThanAttribute : ValidationAttribute, IClientModelValidator
{
    public LowerThanAttribute(string dependentPropertyName)
    {
        DependentPropertyName = dependentPropertyName;
    }

    public string DependentPropertyName { get; set; }

    public void AddValidation(ClientModelValidationContext context)
    {
        var displayCurrentProperyName = context.ModelMetadata.ContainerMetadata
                                            .ModelType.GetProperty(context.ModelMetadata.PropertyName)
                                            .GetCustomAttributes(typeof(DisplayAttribute), false)
                                            .Cast<DisplayAttribute>()
                                            .FirstOrDefault()?.Name;

        var displayDependentProperyName = context.ModelMetadata.ContainerMetadata
                                            .ModelType.GetProperty(DependentPropertyName)
                                            .GetCustomAttributes(typeof(DisplayAttribute), false)
                                            .Cast<DisplayAttribute>()
                                            .FirstOrDefault()?.Name;


        MergeAttribute(context.Attributes, "data-val", "true");
        MergeAttribute(context.Attributes, "data-val-lowerthan", $"{displayCurrentProperyName} باید کمتر باشد از {displayDependentProperyName}");
        MergeAttribute(context.Attributes, "data-val-dependentpropertyname", "#" + DependentPropertyName);
    }
    private  bool MergeAttribute(IDictionary<string, string> attributes, string key, string value)
    {
        if (attributes.ContainsKey(key))
        {
            return false;
        }
        attributes.Add(key, value);
        return true;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        int? currentPropertyValue = value as int?;
        currentPropertyValue ??= 0;
        var typeInfo = validationContext.ObjectInstance.GetType();
        var dependentPropertyValue = Convert.ToInt32(typeInfo.GetProperty(DependentPropertyName)
                                        .GetValue(validationContext.ObjectInstance, null));

        var displayCurrentProperyName = typeInfo.GetProperty(DependentPropertyName)
                                        .GetCustomAttributes(typeof(DisplayAttribute), false)
                                        .Cast<DisplayAttribute>()
                                        .FirstOrDefault()?.Name;

        if (!(currentPropertyValue.Value < dependentPropertyValue))
        {
            return new ValidationResult("مقدار {0} باید کمتر باشد از " + displayCurrentProperyName);
        }
        return ValidationResult.Success;
    }
}
اینترفیس IClientModelValidator، یک متد به نام AddValidation دارد که این امکان را فراهم میکند تا بتوانیم اعتبارسنجی را در سمت کلاینت انجام دهیم. در ادامه باید با استفاده از JQuery اعتبارسنجی مخصوص این ویژگی را در سمت کلاینت پیاده سازی کنیم. در متد AddValidation فقط اسم تابع و پارامتر‌های مورد نیاز در سمت کلاینت را مشخص میکنیم. به عنوان مثال در مثال بالا یک تابع را معرفی کرده‌ایم به نام lowerthan که بعدا باید آنرا در سمت کلاینت پیاده سازی کنیم و نام خاصیتی را که باید با آن مقایسه شود، با نام data-val-dependentpropertyname معرفی کرده‌ایم. در کد زیر، این اعتبار سنجی سمت کلاینت را پیاده سازی کرده ایم. lowerthan نام متدی است که آنرا در متد AddValidation اضافه کردیم. مقدار value همان مقدار خاصیتی است که ویژگی LowerThan بر روی آن قرار دارد و otherPropId نام خاصیتی است که باید با آن مقایسه شود که آنرا از element خوانده‌ایم:
jQuery.validator.addMethod("lowerthan", function (value, element, param) {
    var otherPropId = $(element).data('val-dependentpropertyname');
    if (otherPropId) {
        var otherProp = $(otherPropId);
        if (otherProp) {
            var otherVal = otherProp.val();
            if (parseInt(otherVal) > parseInt(value)) {
                return true;
            }
            return false;
        }
    }
    return true;
});
jQuery.validator.unobtrusive.adapters.addBool("lowerthan");
کدهای جاواسکریپتی بالا را در یک فایل جدید به نام LowerThan.js ذخیره کرده‌ایم که باید آن را به صفحه خود اضافه کنیم:
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
<script src="~/js/LowerThan.js"></script>
سپس برای استفاده، باید ویژگی LowerThan را بر روی خاصیت مورد نظر قرار دهیم؛ مانند زیر:
public class User
{
    [Required]
    [Display(Name ="نام کاربری")]
    public string Username { get; set; }
    [Required]
    [Display(Name = "سن")]
    public int Age { get; set; }
    [LowerThan(nameof(Age))]
    [Required]
    [Display(Name = "سابقه کار")]
    public int Experience { get; set; }
}
و در نهایت اگر مقدار خاصیت Experience که ویژگی LowerThan بر روی آن قرار دارد، از مقدار خاصیت Age که باید با آن مقایسه شود، کمتر باشد، true برگردانده میشود؛ اما اگر بزرگتر یا مساوی باشد، متن خطایی را که در متد AddValidation اضافه کردیم، نشان داده خواهد شد.
 

مطالب
معرفی JSON Web Token


دو روش کلی و پرکاربرد اعتبارسنجی سمت سرور، برای برنامه‌های سمت کاربر وب وجود دارند:
الف) Cookie-Based Authentication که پرکاربردترین روش بوده و در این حالت به ازای هر درخواست، یک کوکی جهت اعتبارسنجی کاربر به سمت سرور ارسال می‌شود (و برعکس).


ب) Token-Based Authentication که بر مبنای ارسال یک توکن امضاء شده به سرور، به ازای هر درخواست است.


مزیت‌های استفاده‌ی از روش مبتنی بر توکن چیست؟

 • Cross-domain / CORS: کوکی‌ها و CORS آنچنان با هم سازگاری ندارند؛ چون صدور یک کوکی وابسته‌است به دومین مرتبط به آن و استفاده‌ی از آن در سایر دومین‌ها عموما پذیرفته شده نیست. اما روش مبتنی بر توکن، وابستگی به دومین صدور آن‌را ندارد و اصالت آن بر اساس روش‌های رمزنگاری تصدیق می‌شود.
 • بدون حالت بودن و مقیاس پذیری سمت سرور: در حین کار با توکن‌ها، نیازی به ذخیره‌ی اطلاعات، داخل سشن سمت سرور نیست و توکن موجودیتی است خود شمول (self-contained). به این معنا که حاوی تمام اطلاعات مرتبط با کاربر بوده و محل ذخیره‌ی آن در local storage و یا کوکی سمت کاربر می‌باشد.
 • توزیع برنامه با CDN: حین استفاده از روش مبتنی بر توکن، امکان توزیع تمام فایل‌های برنامه (جاوا اسکریپت، تصاویر و غیره) توسط CDN وجود دارد و در این حالت کدهای سمت سرور، تنها یک API ساده خواهد بود.
 • عدم در هم تنیدگی کدهای سمت سرور و کلاینت: در حالت استفاده‌ی از توکن، این توکن می‌تواند از هرجایی و هر برنامه‌ای صادر شود و در این حالت نیازی نیست تا وابستگی ویژه‌ای بین کدهای سمت کلاینت و سرور وجود داشته باشد.
 • سازگاری بهتر با سیستم‌های موبایل: در حین توسعه‌ی برنامه‌های بومی پلتفرم‌های مختلف موبایل، کوکی‌ها روش مطلوبی جهت کار با APIهای سمت سرور نیستند. تطابق یافتن با روش‌های مبتنی بر توکن در این حالت ساده‌تر است.
 • CSRF: از آنجائیکه دیگر از کوکی استفاده نمی‌شود، نیازی به نگرانی در مورد حملات CSRF نیست. چون دیگر برای مثال امکان سوء استفاده‌ی از کوکی فعلی اعتبارسنجی شده، جهت صدور درخواست‌هایی با سطح دسترسی شخص لاگین شده وجود ندارد؛ چون این روش کوکی را به سمت سرور ارسال نمی‌کند.
 • کارآیی بهتر: حین استفاده‌ی از توکن‌ها، به علت ماهیت خود شمول آن‌ها، رفت و برگشت کمتری به بانک اطلاعاتی صورت گرفته و سرعت بالاتری را شاهد خواهیم بود.
 • امکان نوشتن آزمون‌های یکپارچگی ساده‌تر: در حالت استفاده‌ی از توکن‌ها، آزمودن یکپارچگی برنامه، نیازی به رد شدن از صفحه‌ی لاگین را ندارد و پیاده سازی این نوع آزمون‌ها ساده‌تر از قبل است.
 • استاندارد بودن: امروزه همینقدر که استاندارد JSON Web Token را پیاده سازی کرده باشید، امکان کار با انواع و اقسام پلتفرم‌ها و کتابخانه‌ها را خواهید یافت.


اما JWT یا JSON Web Token چیست؟

JSON Web Token یا JWT یک استاندارد وب است (RFC 7519) که روشی فشرده و خود شمول (self-contained) را جهت انتقال امن اطلاعات، بین مقاصد مختلف را توسط یک شیء JSON، تعریف می‌کند. این اطلاعات، قابل تصدیق و اطمینان هستند؛ از این‌رو که به صورت دیجیتال امضاء می‌شوند. JWTها توسط یک کلید مخفی (با استفاده از الگوریتم HMAC) و یا یک جفت کلید خصوصی و عمومی (توسط الگوریتم RSA) قابل امضاء شدن هستند.
در این تعریف، واژه‌هایی مانند «فشرده» و «خود شمول» بکار رفته‌اند:
 - «فشرده بودن»: اندازه‌ی شیء JSON یک توکن در این حالت کوچک بوده و به سادگی از طریق یک URL و یا پارامترهای POST و یا داخل یک HTTP Header قابل ارسال است و به دلیل کوچک بودن این اندازه، انتقال آن نیز سریع است.
 - «خود شمول»: بار مفید (payload) این توکن، شامل تمام اطلاعات مورد نیاز جهت اعتبارسنجی یک کاربر است؛ تا دیگر نیازی به کوئری گرفتن هر باره‌ی از بانک اطلاعاتی نباشد (در این روش مرسوم است که فقط یکبار از بانک اطلاعاتی کوئری گرفته شده و اطلاعات مرتبط با کاربر را امضای دیجیتال کرده و به سمت کاربر ارسال می‌کنند).


چه زمانی بهتر است از JWT استفاده کرد؟

اعتبارسنجی: اعتبارسنجی یک سناریوی متداول استفاده‌ی از JWT است. زمانیکه کاربر به سیستم لاگین کرد، هر درخواست بعدی او شامل JWT خواهد بود که سبب می‌شود کاربر بتواند امکان دسترسی به مسیرها، صفحات و منابع مختلف سیستم را بر اساس توکن دریافتی، پیدا کند. برای مثال روش‌های «Single Sign On» خود را با JWT انطباق داده‌اند؛ از این جهت که سربار کمی را داشته و همچنین به سادگی توسط دومین‌های مختلفی قابل استفاده هستند.
انتقال اطلاعات: توکن‌های با فرمت JWT، روش مناسبی جهت انتقال اطلاعات امن بین مقاصد مختلف هستند؛ زیرا قابل امضاء بوده و می‌توان اطمینان حاصل کرد که فرستنده دقیقا همانی است که ادعا می‌کند و محتوای ارسالی دست نخورده‌است.


ساختار یک JWT به چه صورتی است؟

JWTها دارای سه قسمت جدا شده‌ی با نقطه هستند؛ مانند xxxxx.yyyyy.zzzzz و شامل header، payload و signature می‌باشند.
الف) Header
Header عموما دارای دو قسمت است که نوع توکن و الگوریتم مورد استفاده‌ی توسط آن را مشخص می‌کند:
 {
   "alg": "HS256",
   "typ": "JWT"
}
نوع توکن در اینجا JWT است و الگوریتم‌های مورد استفاده، عموما  HMAC SHA256 و یا RSA هستند.

ب) payload
payload یا «بار مفید» توکن، شامل claims است. منظور از claims، اطلاعاتی است در مورد موجودیت مدنظر (عموما کاربر) و یک سری متادیتای اضافی. سه نوع claim وجود دارند:
Reserved claims: یک سری اطلاعات مفید و از پیش تعیین شده‌ی غیراجباری هستند؛ مانند:
iss یا صادر کنند (issuer)، exp یا تاریخ انقضاء، sub یا عنوان (subject) و aud یا مخاطب (audience)
 Public claims: می‌تواند شامل اطلاعاتی باشد که توسط IANA JSON Web Token Registry پیشتر ثبت شده‌است و فضاهای نام آن‌ها تداخلی نداشته باشند.
Private claims: ادعای سفارشی هستند که جهت انتقال داده‌ها بین مقاصد مختلف مورد استفاده قرار می‌گیرند.
یک نمونه‌ی payload را در اینجا ملاحظه می‌کنید:
 {
   "sub": "1234567890",
   "name": "John Doe",
   "admin": true
}
این اطلاعات (هم header و هم payload)، به صورت base64 انکد شده و به JWT اضافه می‌شوند.

ج) signature
یک نمونه فرمول محاسبه‌ی امضای دیجیتال پیام JWT به صورت ذیل است:
 HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)
در اینجا بر اساس الگوریتم HMAC SHA256، هدر و بار مفید پیام به صورت base64 دریافت و به کمک یک کلید مخفی، محاسبه و به JWT اضافه می‌شود تا توسط آن بتوان اصالت پیام و فرستنده‌ی آن‌را تائید کرد. امضاء نیز در نهایت با فرمت base64 در اینجا انکد می‌شود:


یک نمونه مثال تولید این نوع توکن‌ها را در آدرس https://jwt.io می‌توانید بررسی کنید.
در این سایت اگر به قسمت دیباگر آن مراجعه کنید، برای نمونه قسمت payload آن قابل ویرایش است و تغییرات را بلافاصله در سمت چپ، به صورت انکد شده نمایش می‌دهد.


یک نکته‌ی مهم: توکن‌ها امضاء شده‌اند؛ نه رمزنگاری شده

همانطور که عنوان شد، توکن‌ها از سه قسمت هدر، بار مفید و امضاء تشکیل می‌شوند (header.payload.signature). اگر از الگوریتم HMACSHA256 و کلید مخفی shhhh برای امضای بار مفید ذیل استفاده کنیم:
 {
   "sub": "1234567890",
   "name": "Ado Kukic",
   "admin": true
}
یک چنین خروجی باید حاصل شود:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFkbyBLdWtpYyIsImFkbWluIjp0cnVlLCJpYXQiOjE0NjQyOTc4ODV9.Y47kJvnHzU9qeJIN48_bVna6O0EDFiMiQ9LpNVDFymM
در اینجا باید دقت داشت که هدر و بار مفید آن، صرفا با الگوریتم base64 انکد شده‌اند و این به معنای رمزنگاری نیست. به عبارتی می‌توان اطلاعات کامل هدر و بار مفید آن‌را به دست آورد. بنابراین هیچگاه اطلاعات حساسی را مانند کلمات عبور، در اینجا ذخیره نکنید.
البته امکان رمزنگاری توسط JSON Web Encryption نیز پیش بینی شده‌است (JWE).


از JWT در برنامه‌ها چگونه استفاده می‌شود؟

زمانیکه کاربر، لاگین موفقی را به سیستم انجام می‌دهد، یک توکن امن توسط سرور صادر شده و با فرمت JWT به سمت کلاینت ارسال می‌شود. این توکن باید به صورت محلی در سمت کاربر ذخیره شود. عموما از local storage برای ذخیره‌ی این توکن استفاده می‌شود؛ اما استفاده‌ی از کوکی‌ها نیز منعی ندارد. بنابراین دیگر در اینجا سشنی در سمت سرور به ازای هر کاربر ایجاد نمی‌شود و کوکی سمت سروری به سمت کلاینت ارسال نمی‌گردد.
سپس هر زمانیکه کاربری قصد داشت به یک صفحه یا محتوای محافظت شده دسترسی پیدا کند، باید توکن خود را به سمت سرور ارسال نماید. عموما اینکار توسط یک header سفارشی Authorization به همراه Bearer schema صورت می‌گیرد و یک چنین شکلی را دارد:
 Authorization: Bearer <token>
این روش اعتبارسنجی، بدون حالت (stateless) است؛ از این جهت که وضعیت کاربر، هیچگاه در سمت سرور ذخیره نمی‌گردد. API سمت سرور، ابتدا به دنبال هدر Authorization فوق، در درخواست دریافتی می‌گردد. اگر یافت شد و اصالت آن تائید شد، کاربر امکان دسترسی به منبع محافظت شده را پیدا می‌کند. نکته‌ی مهم اینجا است که چون این توکن‌ها «خود شمول» هستند و تمام اطلاعات لازم جهت اعطای دسترسی‌های کاربر به او، در آن وجود دارند، دیگر نیازی به رفت و برگشت به بانک اطلاعاتی، جهت تائید این اطلاعات تصدیق شده، نیست. به همین جهت کارآیی و سرعت بالاتری را نیز به همراه خواهند داشت.


نگاهی به محل ذخیره سازی JWT و نکات مرتبط با آن

محل متداول ذخیره‌ی JWT ها، در local storage مرورگرها است و در اغلب سناریوها نیز به خوبی کار می‌کند. فقط باید دقت داشت که local storage یک sandbox است و محدود به دومین جاری برنامه و از طریق برای مثال زیر دامنه‌های آن قابل دسترسی نیست. در این حالت می‌توان JWT را در کوکی‌های ایجاد شده‌ی در سمت کاربر نیز ذخیره کرد که چنین محدودیتی را ندارند. اما باید دقت داشت که حداکثر اندازه‌ی حجم کوکی‌ها 4 کیلوبایت است و با افزایش claims ذخیره شده‌ی در یک JWT و انکد شدن آن، این حجم ممکن است از 4 کیلوبایت بیشتر شود. بنابراین باید به این نکات دقت داشت.
امکان ذخیره سازی توکن‌ها در session storage مرورگرها نیز وجود دارد. session storage بسیار شبیه است به local storage اما به محض بسته شدن مرورگر، پاک می‌شود.
اگر از local storage استفاده می‌کنید، حملات Cross Site Request Forgery در اینجا دیگر مؤثر نخواهند بود. اما اگر به حالت استفاده‌ی از کوکی‌ها برای ذخیره‌ی توکن‌ها سوئیچ کنید، این مساله همانند قبل خواهد بود و مسیر است. در این حالت بهتر است طول عمر توکن‌ها را تاحد ممکن کوتاه تعریف کنید تا اگر اطلاعات آن‌ها فاش شد، به زودی بی‌مصرف شوند.


انقضاء و صدور مجدد توکن‌ها به چه صورتی است؟

توکن‌های بدون حالت، صرفا بر اساس بررسی امضای پیام رسیده کار می‌کنند. به این معنا که یک توکن می‌تواند تا ابد معتبر باقی بماند. برای رفع این مشکل باید exp یا تاریخ انقضای متناسبی را به توکن اضافه کرد. برای برنامه‌های حساس این عدد می‌تواند 15 دقیقه باشد و برای برنامه‌های کمتر حساس، چندین ماه.
اما اگر در این بین قرار به ابطال سریع توکنی بود چه باید کرد؟ (مثلا کاربری را در همین لحظه غیرفعال کرده‌اید)
یک راه حل آن، ثبت رکورد‌های تمام توکن‌های صادر شده در بانک اطلاعاتی است. برای این منظور می‌توان یک فیلد id مانند را به توکن اضافه کرد و آن‌را صادر نمود. این idها را نیز در بانک اطلاعاتی ذخیره می‌کنیم. به این ترتیب می‌توان بین توکن‌های صادر شده و کاربران و اطلاعات به روز آن‌ها ارتباط برقرار کرد. در این حالت برنامه علاوه بر بررسی امضای توکن، می‌تواند به لیست idهای صادر شده و ذخیره شده‌ی در دیتابیس نیز مراجعه کرده و اعتبارسنجی اضافه‌تری را جهت باطل کردن سریع توکن‌ها انجام دهد. هرچند این روش دیگر آنچنان stateless نیست، اما با دنیای واقعی سازگاری بیشتری دارد.


حداکثر امنیت JWTها را چگونه می‌توان تامین کرد؟

- تمام توکن‌های خود را با یک کلید قوی، امضاء کنید و این کلید تنها باید بر روی سرور ذخیره شده باشد. هر زمانیکه سرور توکنی را از کاربر دریافت می‌کند، این سرور است که باید کار بررسی اعتبار امضای پیام رسیده را بر اساس کلید قوی خود انجام دهد.
- اگر اطلاعات حساسی را در توکن‌ها قرار می‌دهید، باید از JWE یا JSON Web Encryption استفاده کنید؛ زیرا JWTها صرفا دارای امضای دیجیتال هستند و نه اینکه رمزنگاری شده باشند.
- بهتر است توکن‌ها را از طریق ارتباطات غیر HTTPS، ارسال نکرد.
- اگر از کوکی‌ها برای ذخیره سازی آن‌ها استفاده می‌کنید، از HTTPS-only cookies استفاده کنید تا از Cross-Site Scripting XSS attacks در امان باشید.
- مدت اعتبار توکن‌های صادر شده را منطقی انتخاب کنید.
مطالب
معرفی Kendo UI
Kendo UI چیست؟
Kendo UI یک فریم ورک جاوا اسکریپتی ساخت برنامه‌های مدرن و تعاملی وب است و برای رسیدن به این مقصود، از JavaScript، CSS 3، HTML 5 و jQuery کمک می‌گیرد.


امکانات فراهم شده توسط Kendo UI
1) انواع و اقسام ویجت‌ها: کنترل‌های وب تهیه شده برفراز jQuery
ویجت‌های آن در سه گروه کلی قرار می‌گیرند:
- گروه وب، مانند گرید، tree-view و غیره.
- گروه DataViz که جهت نمایش بصری اطلاعات و ترسیم انواع و اقسام نمودارها کاربرد دارد.
- گروه موبایل که با استفاده از فناوری adaptive rendering، در سیستم عامل‌های مختلف موبایل، مانند اندروید و آی او اس، ظاهری بومی و هماهنگ با آن‌ها را ارائه می‌دهد.

2) منبع داده سمت کاربر (Client side data source)
منبع داده سمت کاربر Kendo UI، از انواع و اقسام منابع داده محلی مانند آرایه‌های جاوا اسکریپتی تا منابع داده راه دور، مانند JSON، XML و JSONP، جهت نمایش اطلاعات و data binding پشتیبانی می‌کند. این منبع داده، مواردی مانند صفحه بندی، مرتب سازی اطلاعات و گروه بندی آن‌ها را نیز فراهم می‌کند. به علاوه با عملیات ثبت، ویرایش و حذف اطلاعات نیز هماهنگی کاملی را دارد.

3) به همراه یک فریم ورک MVVM توکار است
این فریم ورک MVVM مواردی مانند two way data binding و همچنین declarative binding را نیز پشتیبانی می‌کند.

4) امکان تعویض قالب
5) پویا نمایی، کشیدن و رها کردن
6) فریم ورک اعتبارسنجی


چرا Kendo UI؟
-  مهم‌ترین مزیت کار با Kendo UI، فراهم آوردن تمام نیازهای توسعه‌ی یک برنامه‌ی مدرن وب، تنها در یک بسته است. به این ترتیب دیگر نیازی نیست تا گرید را از یک‌جا، tree-view را از جایی دیگر و کتابخانه‌های رسم نمودار را از منبعی ناهمگون با سایر عناصر برنامه دریافت و استفاده کنید؛ در اینجا تمام این‌ها در قالب یک بسته‌ی آماده برای شما فراهم شده‌است و همچنین با یکدیگر سازگاری کاملی دارند.
- تمام ویجت‌های آن برای نمایش سریع با کارآیی بالا طراحی شده‌اند.
- پشتیبانی خوب آن. این فریم ورک محصول شرکتی است که به صورت تخصصی کار تهیه کامپوننت‌های وب و دسکتاپ را انجام می‌دهد.


مرورگرهای پشتیبانی شده
یکی دیگر از مزایای مهم کار با Kendo UI پشتیبانی گسترده‌ی آن از اکثر مرورگرهای موجود است. این فریم ورک با مرورگرهای زیر سازگار است:
- IE 7 به بعد
- فایرفاکس 10 به بعد
- تمام نگارش‌های کروم
- اپرا 10 به بعد
- سفاری 4 به بعد


مجوز استفاده از Kendo UI
Kendo UI با سه مجوز ذیل ارائه می‌شود:
- 30 روزه آزمایشی رایگان
- تجاری
- سورس باز با مجوز Apache

پیشتر نسخه‌ی تجاری آن تحت مجوز GPL نیز در دسترس بود. اما اخیرا مجوز GPL آن حذف شده و به Apache تغییر یافته است. اما باید در نظر داشت که نسخه‌ی سورس باز آن شامل کنترل‌های مهمی مانند «گرید» نیست و این موارد تنها در نسخه‌ی تجاری آن لحاظ شده‌اند.


مثال‌های Kendo UI
پس از دریافت بسته‌ی کامل آن، پوشه‌هایی مانند js، styles و امثال آن قابل مشاهده هستند؛ به همراه پوشه‌ی examples آن که حداقل 86 پوشه‌ی دیگر در آن جهت ارائه مثال‌هایی از نحوه‌ی کاربرد المان‌های مختلف آن تدارک دیده شده‌اند.


نحوه‌ی افزودن Kendo UI به صفحه
از آنجائیکه Kendo UI یک فریم ورک جاوا اسکریپتی است، همانند سایر برنامه‌های وب، افزودن تعاریف فایل‌های js، css و تصاویر مرتبط با آن، برای شروع به کار کفایت می‌کند. برای این منظور ابتدا پوشه‌های js و styles بسته‌ی دریافتی آن‌را به برنامه‌ی خود اضافه کنید (این پوشه‌ها در فایل پیوست انتهای بحث موجود هستند).
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>

    <!--KendoUI: Web-->
    <link href="styles/kendo.common.min.css" rel="stylesheet" type="text/css" />
    <link href="styles/kendo.default.min.css" rel="stylesheet" type="text/css" />
    <script src="js/jquery.min.js" type="text/javascript"></script>
    <script src="js/kendo.web.min.js" type="text/javascript"></script>

    <!--KendoUI: DataViz-->
    <link href="styles/kendo.dataviz.min.css" rel="stylesheet" type="text/css" />
    <script src="js/kendo.dataviz.min.js" type="text/javascript"></script>

    <!--KendoUI: Mobile-->
    <link href="styles/kendo.mobile.all.min.css" rel="stylesheet" type="text/css" />
    <script src="js/kendo.mobile.min.js" type="text/javascript"></script>

    <script type="text/javascript">
        $(function() {
            $("#pickDate").kendoDatePicker();
        });
    </script>
</head>
<body>
    <span>
        Pick a date: <input id="pickDate" type="text"/>
    </span>
</body>
</html>
در اینجا یک مثال ساده‌ی استفاده از date picker کندو یو آی را ملاحظه می‌کنید. در قسمت head صفحه، نحوه‌ی ثبت سه گروه اسکریپت و شیوه نامه، مشخص شده‌اند. اگر نیاز به کامپوننت‌های وب آن‌را دارید باید اجزایی مانند kendo.common.min.css، kendo.default.min.css، jquery.min.js و kendo.web.min.js به صفحه اضافه شوند. اگر نیاز به رسم نمودار هست، فایل‌ها kendo.dataviz.min.css و kendo.dataviz.min.js باید تعریف شوند و برای فعال سازی اجزای موبایل آن فایل‌های kendo.mobile.all.min.css و kendo.mobile.min.js نیاز است به صفحه پیوست شوند. در هر سه حالت ذکر jquery.min.js الزامی است.

دریافت سورس کامل این قسمت که حاوی فایل‌های اصلی kendoui.professional.2014.2.1008 نیز می‌باشد:
KendoUI01.7z
اشتراک‌ها
چگونه کوئری های SQL بهتری بنویسیم؟

SQL is far from dead: it’s one of the most in-demand skills that you find in job descriptions from the data science industry, whether you’re applying for a data analyst, a data engineer, a data scientist or any other roles. This is confirmed by 70% of the respondents of the 2016 O’Reilly Data Science Salary Survey, who indicate that they use SQL in their professional context.  

چگونه کوئری های SQL بهتری بنویسیم؟
نظرات مطالب
امن سازی درخواست‌های ای‌جکسی برنامه‌های ASP.NET MVC 5.x در مقابل حملات CSRF
این روش عمومی‌تر است:
function addToken(data) {
   data.__RequestVerificationToken = $("input[name=__RequestVerificationToken]").val();
   return data;
}
برای
$.ajax({
   // .....
   data: addToken({ postId: postId }), // اضافه کردن توکن
   dataType: "html", // نوع داده مهم است
   // .....
});
که معادل قطعه کد زیر هست:
 data: { "pid": pid, "__RequestVerificationToken": $('[name=__RequestVerificationToken]').val()  },
البته به نظر در این حالت "dataType: "html باشد تا کار کند.
حالت سراسری آن هم تحت نظر قرار دادن رخ‌داد مخصوص ارسال‌های Ajax ای هست (نوشتن یک interceptor):
$(document).ready(function () {
            var securityToken = $('[name=__RequestVerificationToken]').val();
            $('body').bind('ajaxSend', function (elm, xhr, s) {
                if (s.type == 'POST' && typeof securityToken != 'undefined') {
                    if (s.data.length > 0) {
                        s.data += "&__RequestVerificationToken=" + encodeURIComponent(securityToken);
                    }
                    else {
                        s.data = "__RequestVerificationToken=" + encodeURIComponent(securityToken);
                    }
                }
            });
        });
مطالب
یک دست سازی ی و ک در برنامه‌های Entity framework 6
تا قبل از EF 6 برای طراحی یک سیستم عمومی تغییر مقادیر ثبت شده در بانک اطلاعاتی، می‌شد با استفاده از امکانات توکار Tracking آن، مقادیر تغییر کرده را یافت و برای مثال ی و ک آن‌ها را پیش از درج در بانک اطلاعاتی، یک دست کرد. در EF 6 با معرفی یک سری interceptor می‌توان به مراحل پیش و پس از اجرای کوئری‌ها دسترسی پیدا کرد. عمده‌ترین کاربرد آن، لاگ کردن SQLهای تولیدی و نوشتن برنامه‌هایی شبیه به EF Profiler است. اما ... استفاده‌ی دیگری را نیز می‌توان از IDbCommandInterceptor جدید آن تدارک دید: دستکاری SQL تولیدی توسط آن پیش از اعمال به بانک اطلاعاتی.

طراحی یک Interceptor برای یک دست سازی ی و ک

در اینجا کدهای کلاس YeKeInterceptor را ملاحظه می‌کنید. در متدهایی که به کلمه‌ی Executing ختم می‌شوند، می‌توان به دستورات SQL تولید شده توسط EF، پیش از اعمال بر روی بانک اطلاعاتی دسترسی داشت:
    public class YeKeInterceptor : IDbCommandInterceptor
    {
        public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
        {
            command.ApplyCorrectYeKe();
        }

        public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
        {
        }

        public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
        {
            command.ApplyCorrectYeKe();
        }

        public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
        {
        }

        public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
        {
        }

        public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
        {
            command.ApplyCorrectYeKe();
        }
    }
DbCommand، حاوی تمام اطلاعاتی است که به آن نیاز داریم؛ شامل CommandText یا همان SQL تولید شده و همچنین command.Parameters برای دسترسی به مقادیر پارامترهای کوئری. نکته‌ی مهم تمام این موارد، قابل ویرایش بودن آن‌ها است.
    public static class YeKe
    {
        public const char ArabicYeChar = (char)1610;
        public const char PersianYeChar = (char)1740;

        public const char ArabicKeChar = (char)1603;
        public const char PersianKeChar = (char)1705;

        public static string ApplyCorrectYeKe(this object data)
        {
            return data == null ? null : ApplyCorrectYeKe(data.ToString());
        }

        public static string ApplyCorrectYeKe(this string data)
        {
            return string.IsNullOrWhiteSpace(data) ?
                        string.Empty :
                        data.Replace(ArabicYeChar, PersianYeChar).Replace(ArabicKeChar, PersianKeChar).Trim();
        }

        public static void ApplyCorrectYeKe(this DbCommand command)
        {
            command.CommandText = command.CommandText.ApplyCorrectYeKe();

            foreach (DbParameter parameter in command.Parameters)
            {
                switch (parameter.DbType)
                {
                    case DbType.AnsiString:
                    case DbType.AnsiStringFixedLength:
                    case DbType.String:
                    case DbType.StringFixedLength:
                    case DbType.Xml:
                        parameter.Value =   parameter.Value is DBNull ? parameter.Value : parameter.Value.ApplyCorrectYeKe();
                        break;
                }
            }
        }
    }
در اینجا پیاده سازی متد الحاقی ApplyCorrectYeKe را که در کلاس YeKeInterceptor مورد استفاده قرار گرفت، ملاحظه می‌کنید.
در آن، CommandText و همچنین parameter.Valueها در صورت رشته‌ای بودن، اصلاح می‌شوند.
سربار این روش نسبت به روش‌های پیشین استفاده از Reflection کمتر است. همچنین اشیاء پیچیده و تو در تو را نیز بهتر پشتیبانی می‌کند؛ چون در مرحله Executing، کار پردازش این اشیاء پایان یافته و SQL خام نهایی آن در اختیار ما است.


نحوه‌ی استفاده از YeKeInterceptor

در آغاز برنامه (برای مثال متد Application_Start فایل Global.asax.cs برنامه‌های MVC )، سطر زیر را فراخوانی کنید:
 DbInterception.Add(new YeKeInterceptor());

یک مثال کامل برای دریافت
Sample32.cs