using System.IdentityModel.Tokens.
Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.AspNetCore.Identity;
using Microsoft.IdentityModel.Tokens;
using dotnetapp.Data;
using dotnetapp.Models;
namespace dotnetapp.Services
{
public class AuthService : IAuthService
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly RoleManager<IdentityRole> _roleManager;
private readonly ApplicationDbContext _db;
private readonly IConfiguration _config;
public AuthService(
UserManager<ApplicationUser> userManager,
RoleManager<IdentityRole> roleManager,
ApplicationDbContext db,
IConfiguration config)
{
_userManager = userManager;
_roleManager = roleManager;
_db = db;
_config = config;
}
public async Task<(int, string)> Registration(User model, string role)
{
// 1) Create identity user -> goes to AspNetUsers
var identityUser = new ApplicationUser
{
UserName = model.Email,
Email = model.Email,
PhoneNumber = model.MobileNumber,
Name = model.Username
};
var created = await _userManager.CreateAsync(identityUser,
model.Password!);
if (!created.Succeeded)
return (0, string.Join("; ", created.Errors.Select(e =>
e.Description)));
// 2) Ensure role exists in AspNetRoles and add link in AspNetUserRoles
if (!await _roleManager.RoleExistsAsync(role))
await _roleManager.CreateAsync(new IdentityRole(role));
await _userManager.AddToRoleAsync(identityUser, role);
// 3) Mirror the user into your custom Users table with SAME
PasswordHash
var custom = new Models.User
{
Username = model.Username,
Email = model.Email,
MobileNumber = model.MobileNumber,
UserRole = role,
PasswordHash = identityUser.PasswordHash ?? string.Empty
// Password left null (never store plaintext)
};
_db.Users.Add(custom);
await _db.SaveChangesAsync();
return (1, "User registered successfully");
}
public async Task<(int, object)> Login(LoginModel model)
{
var identityUser = await _userManager.FindByEmailAsync(model.Email);
if (identityUser == null) return (0, "Invalid email");
var ok = await _userManager.CheckPasswordAsync(identityUser,
model.Password);
if (!ok) return (0, "Invalid password");
var roles = await _userManager.GetRolesAsync(identityUser);
var claims = new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier, identityUser.Id),
new Claim(ClaimTypes.Name, identityUser.UserName ?? string.Empty),
new Claim(ClaimTypes.Email, identityUser.Email ?? string.Empty)
};
claims.AddRange(roles.Select(r => new Claim(ClaimTypes.Role, r)));
var token = GenerateToken(claims);
return (1, new { token });
}
private string GenerateToken(IEnumerable<Claim> claims)
{
var key = new
SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]!));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: _config["Jwt:Issuer"],
audience: _config["Jwt:Audience"],
claims: claims,
expires: DateTime.UtcNow.AddHours(1),
signingCredentials: creds
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
}
}
using Microsoft.AspNetCore.Mvc;
using dotnetapp.Models;
using dotnetapp.Services;
namespace dotnetapp.Controllers
{
[ApiController]
[Route("api")]
public class AuthenticationController : ControllerBase
{
private readonly IAuthService _auth;
public AuthenticationController(IAuthService auth) => _auth = auth;
// POST: /api/register
[HttpPost("register")]
public async Task<IActionResult> Register([FromBody] User model)
{
try
{
if (!ModelState.IsValid) return BadRequest(new { message = "Invalid
payload" });
if (string.IsNullOrWhiteSpace(model.UserRole))
return BadRequest(new { message = "UserRole is required" });
var (code, msg) = await _auth.Registration(model, model.UserRole);
if (code == 1) return StatusCode(201, new { message = msg });
return BadRequest(new { message = msg });
}
catch (Exception ex)
{
return StatusCode(500, new { message = ex.Message });
}
}
// POST: /api/login
[HttpPost("login")]
public async Task<IActionResult> Login([FromBody] LoginModel model)
{
try
{
if (!ModelState.IsValid) return BadRequest(new { message = "Invalid
payload" });
var (code, result) = await _auth.Login(model);
if (code == 1) return StatusCode(201, result);
return BadRequest(new { message = result });
}
catch (Exception ex)
{
return StatusCode(500, new { message = ex.Message });
}
}
}
}