diff options
Diffstat (limited to 'src/Controllers')
| -rw-r--r-- | src/Controllers/AccountController.cs | 116 | ||||
| -rw-r--r-- | src/Controllers/AppControllerBase.cs | 22 |
2 files changed, 138 insertions, 0 deletions
diff --git a/src/Controllers/AccountController.cs b/src/Controllers/AccountController.cs new file mode 100644 index 0000000..7f94711 --- /dev/null +++ b/src/Controllers/AccountController.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Threading.Tasks; +using IOL.WebApi.Template.Data.Database; +using IOL.WebApi.Template.Data.Dtos; +using IOL.WebApi.Template.Data.Result; +using IOL.Helpers; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace IOL.WebApi.Template.Controllers +{ + public class AccountController : AppControllerBase + { + private readonly AppDbContext _context; + private readonly IAuthenticationService _authentication; + + public AccountController( + AppDbContext context, + IAuthenticationService authentication + ) { + _context = context; + _authentication = authentication; + } + + [AllowAnonymous] + [HttpPost("login")] + public ActionResult Login(LoginRequestDto payload) { + if (!ModelState.IsValid) + return BadRequest(ModelState); + var user = _context.Users.SingleOrDefault(u => u.Username == payload.Username); + if (user == default || !user.VerifyPassword(payload.Password)) + return BadRequest(new ErrorResult("Invalid username or password")); + + var claims = new List<Claim> { + new(ClaimTypes.NameIdentifier, user.Id.ToString()), + new(ClaimTypes.Name, user.Username), + }; + + var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); + var principal = new ClaimsPrincipal(identity); + var authenticationProperties = new AuthenticationProperties { + AllowRefresh = true, + IssuedUtc = DateTimeOffset.UtcNow, + }; + + if (payload.Persist) { + authenticationProperties.ExpiresUtc = DateTimeOffset.UtcNow.AddMonths(6); + authenticationProperties.IsPersistent = true; + } + + HttpContext.SignInAsync(principal, authenticationProperties); + return Ok(); + } + + [HttpGet("logout")] + [AllowAnonymous] + public ActionResult Logout() { + HttpContext.SignOutAsync(); + return Ok(); + } + + [AllowAnonymous] + [HttpGet("create-initial")] + public ActionResult CreateInitialUser(string username, string password) { + if (_context.Users.Any()) { + return NotFound(); + } + + var user = new User(username); + user.HashAndSetPassword(password); + _context.Users.Add(user); + _context.SaveChanges(); + return Ok(); + } + + [AllowAnonymous] + [HttpGet("me")] + public async Task<ActionResult> GetLoggedInUser() { + var authres = + await _authentication.AuthenticateAsync(HttpContext, CookieAuthenticationDefaults.AuthenticationScheme); + if (authres.Succeeded) + return Ok(LoggedInUser); + + await HttpContext.SignOutAsync(); + return StatusCode(403); + } + + [HttpPost("update-password")] + public ActionResult UpdatePassword([FromBody] string newPassword) { + if (newPassword.IsNullOrWhiteSpace()) { + return BadRequest(new ErrorResult("Invalid request", + "The new password field is required")); + } + + if (newPassword.Length < 6) { + return BadRequest(new ErrorResult("Invalid request", + "The new password must contain atleast 6 characters")); + } + + var user = _context.Users.SingleOrDefault(c => c.Id == LoggedInUser.Id); + if (user == default) { + HttpContext.SignOutAsync(); + return StatusCode(403); + } + + user.HashAndSetPassword(newPassword); + _context.SaveChanges(); + return Ok(); + } + } +} diff --git a/src/Controllers/AppControllerBase.cs b/src/Controllers/AppControllerBase.cs new file mode 100644 index 0000000..36b52d7 --- /dev/null +++ b/src/Controllers/AppControllerBase.cs @@ -0,0 +1,22 @@ +using System.Linq; +using System.Security.Claims; +using IOL.WebApi.Template.Data.General; +using IOL.Helpers; +using Microsoft.AspNetCore.Mvc; + +namespace IOL.WebApi.Template.Controllers +{ + [ApiController] + [Route("api/[controller]")] + public class AppControllerBase : ControllerBase + { + public string CurrentHost => Request.GetRequestHost(); + + public AppControllerBase() { } + + public LoggedInUser LoggedInUser => new() { + Username = User.Identity?.Name, + Id = User.Claims.SingleOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value.ToGuid() ?? default + }; + } +} |
