هنبدأ نشتغل على مشروع الـ API وهنضيف AccountController جديد فيه الـ Endpoints للإتنين: Login و Register. هنتابع الخطوات دي خطوة بخطوة وهنظبط الأكواد بشكل منظم وكويس.

إنشاء الـ AccountController

أول حاجة، هننشئ AccountController ونسميه كده لأنه هيتعامل مع حسابات المستخدمين. الـ Controller ده هيورث من BaseApiController وهستخدم الـ Services UserManager و SignInManager وهخلي الـ CLR يعمل Inject ليهم.

الكود الأساسي للـ Controller

public class AccountController : BaseApiController
{
    private readonly UserManager<AppUser> _userManager;
    private readonly SignInManager<AppUser> _signInManager;
    
    public AccountController(UserManager<AppUser> userManager, SignInManager<AppUser> signInManager)
    {
        _userManager = userManager;
        _signInManager = signInManager;
    }
}

إضافة الـ Endpoints

هنضيف الـ Endpoints للـ Login و Register داخل الـ Controller.

الـEndpoint بتاع الـ Login

[HttpPost("login")] // POST: /api/account/login
public async Task<ActionResult<UserDto>> Login(LoginDto model)
{
    var user = await _userManager.FindByEmailAsync(model.Email);
    if(user == null)
        return Unauthorized(new ApiResponse(401));
    
    var result = await _signInManager.CheckPasswordSignInAsync(user, model.Password, false);
    if (!result.Succeeded)
        return Unauthorized(new ApiResponse(401));
    
    return Ok(new UserDto
    {
        DisplayName = user.DisplayName,
        Email = user.Email,
        Token = "This will be Token" 
        // هنا هتضيف الكود بتاع الـ JWT Token لاحقًا
    });
}

الـEndpoint بتاع الـ Register

[HttpPost("register")] // POST: /api/account/register
public async Task<ActionResult<UserDto>> Register(RegisterDto model)
{
    var user = new AppUser
    {
        DisplayName = model.DisplayName,
        Email = model.Email,
        UserName = model.Email.Split("@")[0],
        PhoneNumber = model.PhoneNumber
    };
    
    var result = await _userManager.CreateAsync(user, model.Password);
    if(!result.Succeeded) 
        return BadRequest(new ApiResponse(400));
    
    return Ok(new UserDto
    {
        DisplayName = user.DisplayName,
        Email = user.Email,
        Token = "This will be Token" 
        // هنا هتضيف الكود بتاع الـ JWT Token لاحقًا
    });
}

إنشاء الـ DTOs

هنعمل الـ DTOs اللي هنستخدمها في الـ Endpoints. هنحطهم في فولدر اسمه DTOs.

UserDto

using System.ComponentModel.DataAnnotations;
 
public class UserDto
{
    public string DisplayName { get; set; }
    public string Email { get; set; }
    public string Token { get; set; }
}

LoginDto

using System.ComponentModel.DataAnnotations;
 
public class LoginDto
{
    [Required]
    [EmailAddress]
    public string Email { get; set; }
    
    [Required]
    public string Password { get; set; }
}

RegisterDto

using System.ComponentModel.DataAnnotations;
 
public class RegisterDto
{
    [Required]
    public string DisplayName { get; set; }
    
    [Required]
    [EmailAddress]
    public string Email { get; set; }
    
    [Required]
    public string PhoneNumber { get; set; }
    
    [Required]
    [RegularExpression(@"^(?=.*[a-z]{1,})(?=.*[A-Z]{1,})(?=.*\d{1,})(?=.*[!@#$%^&*]).{6,}$", ErrorMessage = "Password is invalid.")]
    public string Password { get; set; }
}

ملاحظات:

  • الـ Regular Expression هنا مبدئيًا وضعتها لتتأكد من إن الباسورد فيها حروف صغيرة وكبيرة وأرقام ورموز خاصة وطولها 6 أحرف على الأقل. تقدر تعدلها حسب احتياجاتك.
  • بدل ما تستخدم الـ Regex في الـ DTO، تقدر تضبط سياسات الباسورد في الـ DI (Dependency Injection) باستخدام إعدادات الـ Identity في Startup.cs أو Program.cs حسب نسخة الـ .NET اللي بتستخدمها. ده هيسهل عملية إدارة سياسات الباسورد ويحسن الأمان. Regex for password - iHateRegex

ضبط سياسات الباسورد في الـ DI

بدل ما تستخدم الـ Regex في الـ DTO، ممكن تضبط سياسات الباسورد في إعدادات الـ Identity. ده بيكون في ملف Startup.cs أو Program.cs حسب البنية بتاعت مشروعك.

مثال في Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    
    services.AddDbContext<DataContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
    
    services.AddIdentity<AppUser, IdentityRole>(options =>
    {
        options.Password.RequireDigit = true;
        options.Password.RequireLowercase = true;
        options.Password.RequireUppercase = true;
        options.Password.RequireNonAlphanumeric = true;
        options.Password.RequiredLength = 6;
    })
    .AddEntityFrameworkStores<DataContext>()
    .AddDefaultTokenProviders();
    
    // باقي الإعدادات
}