167 lines
6.4 KiB
C#
167 lines
6.4 KiB
C#
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.AspNetCore.Razor.TagHelpers;
|
|
using qtc_api.Dtos.User;
|
|
using qtc_api.Services.EmailService;
|
|
using System.IdentityModel.Tokens.Jwt;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Security.Claims;
|
|
using System.Text.Json;
|
|
using ZstdSharp.Unsafe;
|
|
|
|
namespace qtc_api.Controllers
|
|
{
|
|
[Route("api/auth")]
|
|
[ApiController]
|
|
public class AuthController : ControllerBase
|
|
{
|
|
private readonly IUserService _userService;
|
|
private readonly IEmailService _emailService;
|
|
private readonly ITokenService _tokenService;
|
|
private readonly IHubContext<ChatHub> _chatGWContext;
|
|
private readonly IConfiguration _configuration;
|
|
|
|
private readonly ServerConfig serverConfig;
|
|
private readonly DataContext dataContext;
|
|
|
|
public AuthController(IUserService userService, ITokenService tokenService, IHubContext<ChatHub> chatGWContext, DataContext dataContext, IConfiguration configuration, IEmailService emailService)
|
|
{
|
|
_userService = userService;
|
|
_tokenService = tokenService;
|
|
_chatGWContext = chatGWContext;
|
|
_configuration = configuration;
|
|
_emailService = emailService;
|
|
|
|
serverConfig = JsonSerializer.Deserialize<ServerConfig>(JsonDocument.Parse(System.IO.File.ReadAllText("./ServerConfig.json")));
|
|
this.dataContext = dataContext;
|
|
}
|
|
|
|
[HttpPost("register")]
|
|
public async Task<ActionResult<ServiceResponse<User>>> Register(UserDto userDto)
|
|
{
|
|
if(userDto != null)
|
|
{
|
|
var response = await _userService.AddUser(userDto);
|
|
await _chatGWContext.Clients.All.SendAsync("RefreshUserLists");
|
|
if(response.Success != false && response.Data != null)
|
|
{
|
|
// send confirmation email (shouldn't do anything if email confirmation is disabled)
|
|
var confirmationToken = _tokenService.GenerateEmailConfirmationToken(response.Data);
|
|
var confirmationUrl = $"{Request.Scheme}://{Request.Host}/api/auth/verify-email?token={confirmationToken.Data}";
|
|
|
|
await _emailService.SendConfirmationEmail(response.Data.Email, response.Data.Username, confirmationUrl);
|
|
|
|
return Ok(response);
|
|
} else
|
|
{
|
|
return StatusCode(500, response.Message);
|
|
}
|
|
} else
|
|
{
|
|
return BadRequest();
|
|
}
|
|
}
|
|
|
|
[HttpPost("login")]
|
|
public async Task<ActionResult<ServiceResponse<string>>> Login(UserLoginDto request)
|
|
{
|
|
var dbUser = await _userService.GetUserByEmail(request.Email);
|
|
|
|
if (dbUser.Data == null)
|
|
{
|
|
return Ok(new ServiceResponse<string>
|
|
{
|
|
Message = "User not found.",
|
|
Success = false
|
|
});
|
|
} else if(!BCrypt.Net.BCrypt.Verify(request.Password, dbUser.Data.PasswordHash))
|
|
{
|
|
return Ok(new ServiceResponse<string>
|
|
{
|
|
Message = "Incorrect password.",
|
|
Success = false
|
|
});
|
|
}
|
|
|
|
if(!dbUser.Data.IsEmailVerified && _configuration.GetValue<bool>("EmailConfig:EmailConfirmationRequired"))
|
|
{
|
|
return Ok(new ServiceResponse<string>
|
|
{
|
|
Message = "You need to verify your email on this server. Check your inbox or spam. If you have not received an email, click 'Resend Verification Email'",
|
|
Success = false
|
|
});
|
|
}
|
|
|
|
if (dbUser.Data.Id == serverConfig.AdminUserId && dbUser.Data.Role != "Admin")
|
|
{
|
|
dbUser.Data.Role = "Admin";
|
|
dataContext.SaveChanges();
|
|
}
|
|
|
|
if (dbUser.Data.Status == 1)
|
|
{
|
|
return Ok(new ServiceResponse<string>
|
|
{
|
|
Message = "User is already signed in.",
|
|
Success = false
|
|
});
|
|
}
|
|
|
|
var token = await _tokenService.GenerateAccessTokenAndRefreshToken(dbUser.Data, true, request.RememberMe);
|
|
|
|
return Ok(token);
|
|
}
|
|
|
|
[HttpPost("refresh")]
|
|
public async Task<ActionResult<ServiceResponse<string>>> RefreshLogin(string token)
|
|
{
|
|
var response = await _tokenService.ValidateRefreshToken(token);
|
|
return Ok(response);
|
|
}
|
|
|
|
[HttpGet("verify-email")]
|
|
public async Task<ActionResult<string>> VerifyEmail(string token)
|
|
{
|
|
try
|
|
{
|
|
var handler = new JwtSecurityTokenHandler();
|
|
handler.InboundClaimTypeMap = new Dictionary<string, string>();
|
|
|
|
var jwt = handler.ReadJwtToken(token);
|
|
|
|
if (jwt != null)
|
|
{
|
|
var email = jwt.Claims.FirstOrDefault(e => e.Type == ClaimTypes.Email);
|
|
var id = jwt.Claims.FirstOrDefault(e => e.Type == ClaimTypes.NameIdentifier);
|
|
|
|
if (email != null && id != null)
|
|
{
|
|
// get the user from id claim
|
|
var user = await _userService.GetUserById(id.Value);
|
|
if (user != null && user.Success && user.Data != null)
|
|
{
|
|
var now = DateTime.UtcNow;
|
|
if(user.Data.Email == email.Value && now < jwt.ValidTo.ToUniversalTime())
|
|
{
|
|
user.Data.IsEmailVerified = true;
|
|
await dataContext.SaveChangesAsync();
|
|
|
|
return Ok("Email Verified! You may now login on the client.");
|
|
}
|
|
} else
|
|
{
|
|
return Ok("The User This Confirmation Link Is Associated With No Longer Exists.");
|
|
}
|
|
}
|
|
}
|
|
|
|
return Ok("Token Invalid. You may need to be sent another confirmation link.");
|
|
} catch (SecurityTokenMalformedException)
|
|
{
|
|
return Ok("Token Invalid. You may need to be sent another confirmation link.");
|
|
}
|
|
}
|
|
}
|
|
}
|