আজকের লেকচারে স্বাগতম!
কোথায় আছি আমরা? আপনি বর্তমানে Section 25: Identity-তে আছেন। গত লেকচারে আমরা UserManager ব্যবহার করে ডাটাবেসে নতুন ইউজার সেভ করা শিখেছি। কিন্তু রেজিস্ট্রেশন সফল হওয়ার পর ইউজারকে তো অ্যাপ্লিকেশনে লগইন (Login) করাতে হবে! আজকে আমরা শিখবো SignInManager-এর কাজ, Authentication Cookie কীভাবে কাজ করে এবং UseAuthentication Middleware-এর গুরুত্ব।
📝 Quick Summary for Revision
ভবিষ্যতে দ্রুত রিভিশন দেওয়ার জন্য পুরো লেকচারের মূল বিষয়গুলো নিচে লিস্ট করা হলো:
- SignInManager: এটি লগইন এবং লগআউট-এর Business Logic হ্যান্ডেল করে।
- Key Methods:
SignInAsync(সরাসরি ইউজার অবজেক্ট দিয়ে লগইন),PasswordSignInAsync(ইউজারনেম ও পাসওয়ার্ড দিয়ে লগইন),SignOutAsync(লগআউট)। - Authentication Cookie: লগইন সফল হলে সার্ভার একটি Cookie তৈরি করে ব্রাউজারে পাঠায়। ব্রাউজার পরবর্তী রিকোয়েস্টগুলোতে এই Cookie সার্ভারে পাঠায়, जिससे সার্ভার ইউজারকে চিনতে পারে।
- isPersistent: Cookie-টি ব্রাউজার বন্ধ করলেও সেভ থাকবে কিনা, তা নির্ধারণ করে (true/false)।
- UseAuthentication Middleware: এটি
Program.cs-এ অ্যাড করতে হয়। এটি ব্রাউজার থেকে আসা Cookie পড়ে ইউজারের পরিচয় বের করে। এটি অবশ্যইUseRouting-এর ঠিক আগে বসাতে হবে। - Display Username: View-তে
User.Identity?.Nameব্যবহার করে লগইন করা ইউজারের নাম দেখানো যায়।
🧠 Comprehensive Breakdown
এখানে লেকচারের প্রতিটি বিষয় বিস্তারিতভাবে এবং ধাপে ধাপে ব্যাখ্যা করা হলো:
১. Introduction to SignInManager (Priority: 10/10)
UserManager যেমন ইউজার তৈরি বা এডিট করার জন্য ব্যবহৃত হয়, ঠিক তেমনি SignInManager ব্যবহৃত হয় ইউজারের লগইন বা সেশন ম্যানেজ করার জন্য।
SignInAsync: যখন আপনার কাছে ইউজারের অবজেক্ট আগে থেকেই থাকে (যেমন রেজিস্ট্রেশন করার ঠিক পরপরই), তখন এটি ব্যবহার করা হয়।PasswordSignInAsync: যখন ইউজার লগইন পেজে এসে ইউজারনেম এবং পাসওয়ার্ড দেয়, তখন এই মেথড কল করতে হয়।SignOutAsync: ইউজারকে লগআউট করার জন্য।IsSignedIn: বর্তমান ইউজার লগইন করা অবস্থায় আছে কিনা তা চেক করার জন্য।
২. How Cookie Authentication Works (Priority: 9/10)
লগইন আসলে কীভাবে কাজ করে?
- যখন
SignInAsyncকল করা হয়, সার্ভার ইউজারের ডেটা (ID, Name) এনক্রিপ্ট করে একটি Authentication Cookie তৈরি করে। - সার্ভার সেই Cookie-টিকে HTTP Response-এর সাথে ব্রাউজারে পাঠিয়ে দেয়। ব্রাউজার এটি সেভ করে রাখে।
- এরপর ইউজার যখন অন্য কোনো পেজে (যেমন:
/persons/index) যাওয়ার রিকোয়েস্ট করে, ব্রাউজার অটোমেটিকভাবে সেই Cookie-টিকে রিকোয়েস্টের সাথে সার্ভারে পাঠিয়ে দেয়। - সার্ভার তখন Cookie ডি-ক্রিপ্ট করে বুঝতে পারে যে ইউজার আগে থেকেই লগইন করা আছে।
৩. Injecting and Using SignInManager (Priority: 10/10)
রেজিস্ট্রেশনের পর ইউজারকে অটো-লগইন করানোর জন্য আমাদের AccountController-এ SignInManager ইনজেক্ট করতে হবে।
💻 Code Implementation:
using Microsoft.AspNetCore.Identity;
public class AccountController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager; // নতুন ফিল্ড
// Constructor Injection
public AccountController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager)
{
_userManager = userManager;
_signInManager = signInManager;
}
[HttpPost]
public async Task<IActionResult> Register(RegisterDTO registerDTO)
{
// ... (আগের কোড: Validation এবং CreateAsync) ...
IdentityResult result = await _userManager.CreateAsync(user, registerDTO.Password);
if (result.Succeeded)
{
// Registration সফল হলে অটোমেটিক Sign-in করানো হচ্ছে
bool isPersistent = false; // ব্রাউজার ক্লোজ করলে লগআউট হয়ে যাবে
await _signInManager.SignInAsync(user, isPersistent);
return RedirectToAction("Index", "Persons");
}
// ... (Error handling) ...
}
}
isPersistent Parameter: এর ভ্যালু true দিলে Cookie-টি পার্মানেন্ট হবে (ব্রাউজার কাটলেও লগইন থাকবে, যেমন: জিমেইলে হয়)। false দিলে এটি একটি Session Cookie হবে, অর্থাৎ ব্রাউজার বন্ধ করলেই লগআউট হয়ে যাবে। সাধারণত লগইন পেজে “Keep me signed in” চেকবক্সের মাধ্যমে এটি কন্ট্রোল করা হয়।
৪. Accessing the Logged-in User in the View (Priority: 8/10)
লগইন করার পর, আমরা চাই হেডারে বা লেআউটে ইউজারের নাম দেখাতে। ASP.NET Core-এ View-এর ভেতর User (যা ClaimsPrincipal টাইপের) নামের একটি বিল্ট-ইন প্রপার্টি থাকে।
💻 Code Implementation (_Layout.cshtml):
<ul>
<li>
@* Null-conditional operator (?) ব্যবহার করা হয়েছে যাতে লগইন না থাকলে এরর না দেয় *@
@User.Identity?.Name
</li>
<li><a asp-controller="Account" asp-action="Register">Register</a></li>
</ul>
এখানে ? (null conditional operator) ব্যবহার করা হয়েছে। কারণ, যদি কেউ লগইন না করে থাকে, তবে User.Identity null হবে এবং সরাসরি Name কল করলে অ্যাপ্লিকেশন ক্র্যাশ করবে। ? দেওয়ার ফলে লগইন না থাকলে এটি কিছুই প্রিন্ট করবে না।
৫. The Magic Middleware: app.UseAuthentication (Priority: 10/10)
উপরের কোড লেখার পরও আপনি লেআউটে ইউজারের নাম দেখতে পারবেন না! কারণ, ব্রাউজার Cookie পাঠালেও, আমাদের অ্যাপ্লিকেশনে এমন কেউ নেই যে সেই Cookie পড়ে ইউজারের পরিচয় ডিকোড করবে। এই কাজটাই করে Authentication Middleware।
💻 Code Implementation (Program.cs - .NET 10 Context):
var app = builder.Build();
// ... অন্যান্য Middleware (যেমন: StaticFiles) ...
// ক্রমানুসারে এটি UseRouting এর ঠিক আগে বা পরে, কিন্তু UseAuthorization এবং MapControllers এর আগে থাকতে হবে!
app.UseRouting();
app.UseAuthentication(); // <-- এটি Cookie রিড করে ইউজারের পরিচয় বের করে
app.UseAuthorization(); // <-- এটি চেক করে ইউজারের এই পেজে যাওয়ার পারমিশন আছে কিনা
app.MapControllers();
app.Run();
Why the exact order? Middleware-এর সিকোয়েন্স খুব গুরুত্বপূর্ণ। MapControllers (যেটি একচুয়াল Controller-এ রিকোয়েস্ট পাঠায়) কল হওয়ার আগেই UseAuthentication কে Cookie পড়ে ইউজারকে আইডেন্টিফাই করতে হবে। তা না হলে Controller বা View জানতেই পারবে না কে রিকোয়েস্ট করেছে!
৬. Compare Validation in RegisterDTO (Priority: 5/10)
লেকচারার এই ধাপে এসে RegisterDTO-তে Password এবং ConfirmPassword মেলানোর জন্য [Compare] অ্যাট্রিবিউট অ্যাড করেছেন (যা আমি আগের লেকচারের Best Practices-এই উল্লেখ করেছিলাম)।
[Required]
[Compare("Password", ErrorMessage = "Password and confirm password do not match")]
public string ConfirmPassword { get; set; }
🌟 Best Practices for ASP.NET Core MVC
- Always Use
User.Identity.IsAuthenticated: View-তে ইউজারের নাম বা লগআউট বাটন দেখানোর আগে চেক করে নেওয়া ভালো যে ইউজার আদৌ লগইন করা আছে কিনা।
@if (User.Identity.IsAuthenticated)
{
<span>Hello, @User.Identity.Name!</span>
}
else
{
}
- Separation of Concerns: Controller-এর ভেতরে সরাসরি
UserManagerবাSignInManagerব্যবহার করা স্ট্যান্ডার্ড, তবে অনেক বড় প্রজেক্টে এই পুরো Authentication লজিকগুলোকে একটি আলাদা Service ক্লাসে (যেমন:IAuthService) নিয়ে যাওয়া হয়, যেন Controllers একেবারে “Thin” থাকে।
পরবর্তী লেকচারে আমরা UI-কে ডাইনামিক করা শিখবো, যেন ইউজার লগইন করা থাকলে Register/Login বাটনের বদলে Logout বাটন দেখায়!