using AutoMapper; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using Sledgemapper.Entities; using Sledgemapper.Models.Users; using System; using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; using System.Linq; using System.Security.Claims; using System.Text; using System.Threading.Tasks; namespace Sledgemapper.Api.Controllers { [Route("[controller]")] // api/authmanagement [ApiController] public class AuthManagementController : ControllerBase { private readonly UserManager _userManager; private readonly JwtConfig _jwtConfig; private readonly IMapper _mapper; public AuthManagementController(UserManager userManager, IOptionsMonitor optionsMonitor, IMapper mapper) { _userManager = userManager; _jwtConfig = optionsMonitor.CurrentValue; _mapper = mapper; } [HttpPost] [Route("Register")] public async Task Register([FromBody] RegisterModel user) { // Check if the incoming request is valid if (ModelState.IsValid) { // check i the user with the same email exist var existingUser = await _userManager.FindByEmailAsync(user.Email); if (existingUser != null) { return BadRequest(new RegistrationResponse() { Result = false, Errors = new List(){ "Email already exist" } }); } var newUser = _mapper.Map(user); // var newUser = new User() { Email = user.Email, UserName = user.UserName }; var isCreated = await _userManager.CreateAsync(newUser, user.Password); if (isCreated.Succeeded) { var jwtToken = GenerateJwtToken(newUser); return Ok(new RegistrationResponse() { Result = true, Token = jwtToken }); } return new JsonResult(new RegistrationResponse() { Result = false, Errors = isCreated.Errors.Select(x => x.Description).ToList() } ) { StatusCode = 500 }; } return BadRequest(new RegistrationResponse() { Result = false, Errors = new List(){ "Invalid payload" } }); } [HttpPost] [Route("Login")] public async Task Login([FromBody] UserLoginRequest user) { if (ModelState.IsValid) { // check if the user with the same email exist var existingUser = await _userManager.FindByEmailAsync(user.Email); if (existingUser == null) { // We dont want to give to much information on why the request has failed for security reasons return BadRequest(new RegistrationResponse() { Result = false, Errors = new List(){ "Invalid authentication request" } }); } // Now we need to check if the user has inputed the right password var isCorrect = await _userManager.CheckPasswordAsync(existingUser, user.Password); if (isCorrect) { var jwtToken = GenerateJwtToken(existingUser); return Ok(new RegistrationResponse() { Result = true, Token = jwtToken }); } else { // We dont want to give to much information on why the request has failed for security reasons return BadRequest(new RegistrationResponse() { Result = false, Errors = new List(){ "Invalid authentication request" } }); } } return BadRequest(new RegistrationResponse() { Result = false, Errors = new List(){ "Invalid payload" } }); } private string GenerateJwtToken(User user) { // Now its ime to define the jwt token which will be responsible of creating our tokens var jwtTokenHandler = new JwtSecurityTokenHandler(); // We get our secret from the appsettings var key = Encoding.ASCII.GetBytes(_jwtConfig.Secret); // we define our token descriptor // We need to utilise claims which are properties in our token which gives information about the token // which belong to the specific user who it belongs to // so it could contain their id, name, email the good part is that these information // are generated by our server and identity framework which is valid and trusted var tokenDescriptor = new SecurityTokenDescriptor { Subject = new ClaimsIdentity(new[] { new Claim("Id", user.Id.ToString()), new Claim(JwtRegisteredClaimNames.Sub, user.Email), new Claim(JwtRegisteredClaimNames.Email, user.Email), // the JTI is used for our refresh token which we will be convering in the next video new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()) }), // the life span of the token needs to be shorter and utilise refresh token to keep the user signedin // but since this is a demo app we can extend it to fit our current need Expires = DateTime.UtcNow.AddHours(6), // here we are adding the encryption alogorithim information which will be used to decrypt our token SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha512Signature) }; var token = jwtTokenHandler.CreateToken(tokenDescriptor); var jwtToken = jwtTokenHandler.WriteToken(token); return jwtToken; } } }