JSON Web Token Introduction - jwt.io
هنرجع تاني للـ Security Module آخر حاجة عملناها هي الـ Login and Register Endpoints
وكنا واقفين عند جزئية اننا عايزين نعمل Generate للـ Token باستخدام الـ JWT
فكرة الـ Token
الـ Token: عبارة عن Encrypted String -بناخد مجموعة من الـ Inputs ونعديها على Security Algorithm بيبدأ يعملها شوية Equations و Encryption وكدا- وبيطلعلي الـ String بتاعتي وبنقول عليها انها الهوية Identity فلو مفيش Token وعايز ادخل على Netflix واتفرج على فيلم فيقولي انت مين اقوله انا كذا واليوزر بتاعي كذا والباسوورد كذا وبعد ما اخلص الفيلم اعوز اتفرج على فيلم تاني فيسأل انت مين فأبعتله نفس اليوزر والباسوورد وكل شوية كدا فدا مش منطقي انما المنطق بيقول اني اول مرة أعمل Login فالـ Server side يعملي Token ويرجعه للـ End-user اللي هو انا وانا افضل محتفظ بيه وكل مرة اعوز اعمل Request لـ Netflix ابعت الـ Token دا في الـ Request فالـ Request يعدي كل مرة
احنا بنعمل دلوقتي الـ API وهنعمل Run لـ Project الـ Angular فالمفروض ان الـ Front-end developer فهو بيعمل حاجة اسمها Interceptor فالبتاع دا بيحط مناخيرة في كل حاجة (متدخل) فالفرونت اند ديفولوبر بيعمل Implement للـ Interceptor دا اللي هو بيمسك كل Request رايح يكلم كل Endpoint من الـ API والـ Endpoint لازم يكون Authorize عشان يكلمها فالفرونت اند بيخلي الـ Interceptor يعمل Intercept ويمسك الـ Request يلزق فيه الـ Token بشكل اوتوماتيك فأي Request هيحط فيه الـ Token
لما الـ Front-end عمل Consume للـ Login ودخل رجعتله الـ Token
وهو بيروح يخزنه في الـ Local storage أو أي حاجة
النهاردة هنستخدم الـ JWT package
JWT package
JSON Web Token: Encrypted String generated from JSON
بنختار الـ Security Algorithm
التشفير وفك التشفير ببساطة (ABC Encryption)
- البيانات الأصلية (Plaintext):
البيانات التي تريد إرسالها، مثل:
1, 2, 3 - التشفير (Encryption):
استخدام معادلة معينة لتحويل البيانات إلى شكل مشفر، مثل:
إضافة 10 لكل رقم
الناتج: 11, 12, 13 - الإرسال (Transmission):
يتم إرسال البيانات المشفرة بأمان إلى المستقبل. - فك التشفير (Decryption):
لدى المستقبل معادلة عكسية لفك التشفير، مثل:
طرح 10 من كل رقم
فيتم تحويلها إلى الشكل الأصلي: 1, 2, 3
الخلاصة:
التشفير هو عملية تعديل البيانات باستخدام معادلة، بينما فك التشفير يعيد البيانات إلى شكلها الأصلي باستخدام معادلة معاكسة.
Why we use Token
بستخدم الـ Token عشان حاجتين:
- الـ Authentication و Authorization
- الـ Information Exchange: بنعمل الـ Token من خلال شوية Data فلما أبعت الـ Token للـ Front-end ببعت معلومة سرية لحاجة معينة معاه مثلًا باسوورد أو حاجة، فالـ Front-end يعمله Decoding ويطلع المعلومات دي
الـ Token بيتكون من ايه
بيتكون من 3 حاجات:
- الـ Header: بيكون عبارة عن JSON وبيتكون من اتنين Property واحد للـ Algorithm والتاني للـ Token Type
- الـ Payload: الـ Data او الـ Claims وبتكون نوعين:
- ياما Registered claim يعني معروفة predefined وثابتة لكل الـ Users زي الـ Subject وفيه الـ audience اللي هو بتعمله لمين وفيه الـ issuer اللي هو المصدر (اللي عمل التوكين)
- وتاني حاجة عندنا اللي هي الـ Private Claims اللي بتختلف من User للتاني
- ممكن ابعت الـ Password فلما أبعته للـ Front-end يعرف يفك ويعرف الـ Password ودي اللي بنقول عليها Information Exchange
- الـ Signature: فنبدأ نشوف الـ Security Algorithm اللي احنا اخترناه وكأنه بياخد Parameters
Auth Service
اللي هيكون جواها Function بتعمل Refresh Token وهيبقا فيها حاجات كتير بس النهاردة هيبقا بس اللي بتعمل Generate Token
ميزة الـ Refresh Token: قولنا ان الـ Front-end بيخزن الـ Token في الـ Local storage والمفروض انه يحصله Expire في خلال يوم مثلًا، فممكن ياخد الـ Token بتاع واحد وافتحه عندي بنفس الـ Token ودا اللي كان بيحصل مع Watch it فميزته انه بيعمل Expire بعد نص دقيقة وبيتغير كل شوية وبيتعمله Refresh
Interface
نروح في بروجكت الـ Core ونعمل Services.Contract
جديد
public interface IAuthService
{
Task<string> CreateTokenAsync(AppUser user, UserManager<AppUser> userManager);
}
Class
نروح في Project الـ Service
public class AuthService : IAuthService
{
private readonly IConfiguration _configuration;
public AuthService(IConfiguration configuration)
{
_configuration = configuration;
}
public Task<string> CreateTokenAsync(AppUser user, UserManager<AppUser> userManager)
{
// Private Claims
var authClaims = new List<Claim>()
{
new Claim(ClaimTypes.GivenName, user.UserName),
new Claim(ClaimTypes.Email, user.Email)
};
var userRoles = await userManager.GetRolesAsync(user);
foreach (var role in userRoles)
{
authClaims.Add(new Claim(ClaimTypes.Role, role));
}
var authKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JWT:SecretKey"]));
var token = new JwtSecurityToken(
audience: _configuration["JWT:ValidAudience"],
issuer: _configuration["JWT:ValidIssuer"],
expires: DateTime.UtcNow.AddDays(double.Parse(_configuration["JWT:DurationInDays"])),
claims: authClaims,
signingCredentials: new SigningCredentialsI(authKey, SecurityAlgorithms.HmacSha256Signature)
);
// pass to ctor By name
return new JwtSecurityTokenHandler().WriteToken(token);
// Object Member
}
}
// appsettings
"JWT": {
"SecretKey": "StrONGKAutHENTICATIONKEy",
"ValidAudience": "SecuiredApiUsers",
"ValidIssuer": "ALX",
"DurationInDays": 1
}, // don't forget ,
محتاج نعمل Install للـ Package بتاع الـ JWT وهنعمل كدا في الـ Project Services
اسم الـ Package هو Microsoft.AspNetCore.Authentication.JwtBearer
هنبدأ بقا دلوقتي نعرف الـ 3 حاجات اللي قولنا عليهم فوق وأول حاجة هي الـ Claims وخصوصا الـ Private Claims:
- هنعمل var اسمه
authClaims
ويبقا عبارة عن List من النوع اللي اسمه Claim - نبدأ نعمله Initialize وهو بياخد حاجتين الـ type والـ value
ممكن كمان اضيفله الـ Role بتاع الـ User فهضطر اني اخليه ياخد UserManager
فالفرونت لو عايز يعرف يفك الـ Role ويعرف
محتاجين كمان نضيف الـ Secret Key بس احنا مش هنكتب أي داتا هنا فأنا لو محتاج أعملها Configure او حاجة فبعملها في فايل appsettings
فهو بيشيل معلومات ممكن اغيرها في وقت من الأوقات
JwtSecret.com - Generate JWT Secrets Online
دلوقتي المفروض احدد Registered Claims والـ Security Algorithm بس الحاجات دي هحددها وانا ببني الـ Token Object ودا اللي هستخدمه عشان أبني الـ Token
دي الـ Claims اللي بستخدمها عشان اعمل Generate Token ودي برضو اللي هستخدمها عشان أشوف الـ Token صح ولا لا
ممكن استخدم الـ Subject
ممكن نستخدم كمان الـ Expire
هنحتاج نبعت كمان الـ Authentication Claims الـ Private
محتاجين نبعت الـ Secret Key والـ Security Algorithm
دي عبارة عن Common class مبيتعملش غير مرة واحدة للشركة فخد بالك انت ممكن متعملوش اصلا كتير وممكن تسأل السينيورز على حاجات فيه عادي