Benjamin Arhen
2 years ago
17 changed files with 460 additions and 37 deletions
@ -0,0 +1,7 @@ |
|||
namespace Biskilog_Accounting.Client.Pages.Auth |
|||
{ |
|||
public partial class Login |
|||
{ |
|||
|
|||
} |
|||
} |
@ -0,0 +1,39 @@ |
|||
using Biskilog_Accounting.Shared.ClientContractModels; |
|||
using Biskilog_Accounting.Shared.Interfaces; |
|||
using Microsoft.AspNetCore.Http; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.DotNet.Scaffolding.Shared.CodeModifier.CodeChange; |
|||
|
|||
namespace Biskilog_Accounting.Server.Controllers |
|||
{ |
|||
[Route("api/[controller]")]
|
|||
[ApiController] |
|||
public class AuthenticationController : ControllerBase |
|||
{ |
|||
private readonly IAuthService m_authService; |
|||
private readonly ITokenService m_tokenService; |
|||
public AuthenticationController(IAuthService a_authService, ITokenService a_tokenService) |
|||
{ |
|||
m_authService = a_authService; |
|||
m_tokenService = a_tokenService; |
|||
} |
|||
|
|||
[HttpPost, Route("type-a")] |
|||
public async Task<IActionResult> AuthUser(Userauth a_userData) |
|||
{ |
|||
|
|||
if (a_userData != null && a_userData.Username != null && a_userData.Passsword != null) |
|||
{ |
|||
var token = await m_authService.AuthenticateClient(a_userData.Username, a_userData.Passsword); |
|||
|
|||
if (token == null) |
|||
return BadRequest("Invalid credentials"); |
|||
return Ok(token.ToString()); |
|||
} |
|||
else |
|||
{ |
|||
return BadRequest(); |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,141 @@ |
|||
using Biskilog_Accounting.Shared.ClientContractModels; |
|||
using Biskilog_Accounting.Shared.Enums; |
|||
using Biskilog_Accounting.Shared.Interfaces; |
|||
using Microsoft.EntityFrameworkCore; |
|||
|
|||
namespace Biskilog_Accounting.Server.Services |
|||
{ |
|||
public class AuthenticationService : IAuthService |
|||
{ |
|||
private readonly BiskilogContext m_context; |
|||
private readonly ITokenService m_tokenService; |
|||
|
|||
public AuthenticationService(BiskilogContext a_context, ITokenService a_tokenService) |
|||
{ |
|||
m_context = a_context; |
|||
m_tokenService = a_tokenService; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the status of a user account
|
|||
/// </summary>
|
|||
/// <returns>AuthEnums</returns>
|
|||
public AuthEnums AccountStatus(int? a_id, string? a_username) |
|||
{ |
|||
if (m_context.Userauths.Any(i => i.UserId == a_id || i.Username == a_username)) |
|||
{ |
|||
return AuthEnums.Found; |
|||
} |
|||
else |
|||
{ |
|||
return AuthEnums.NotFound; |
|||
} |
|||
} |
|||
/// <summary>
|
|||
/// Autenticates a user and returns a tokenized string
|
|||
/// </summary>
|
|||
/// <param name="a_username"></param>
|
|||
/// <param name="a_password"></param>
|
|||
/// <returns>strings</returns>
|
|||
|
|||
public async Task<string> AuthenticateClient(string a_username, string a_password) |
|||
{ |
|||
var user = await GetUserAsync(a_username, a_password); |
|||
|
|||
if (user == null) |
|||
{ |
|||
return null; |
|||
} |
|||
user.LastLogin = DateTime.Now; |
|||
m_context.Userauths.Update(user); |
|||
m_context.SaveChanges(); |
|||
|
|||
|
|||
Databasemap databasemap = GetClientDB(user.ClientId); |
|||
|
|||
List<int> businessIds = GetSiteaccesspermission(user.ClientId, user.UserId).Select(t => t.BusinessId).ToList(); |
|||
Contract? contract = GetContract(user.ClientId, businessIds); |
|||
|
|||
if (contract == null) |
|||
return AuthEnums.Invalid.ToString(); |
|||
|
|||
return m_tokenService.GenerateToken(user, contract, databasemap); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Creates a new user account
|
|||
/// </summary>
|
|||
/// returns AuthEnums.successful if the account was created successfully
|
|||
public AuthEnums CreateUser(Userauth a_user) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
//if (AccountStatus(null, a_user.Username) == AuthEnums.Found)
|
|||
// return AuthEnums.Registered;
|
|||
|
|||
//a_user.Role = m_context.UserRoles.First(i => i.RoleId== a_user.RoleId);
|
|||
//a_user.Password = BCrypt.Net.BCrypt.HashPassword(a_user.Password);
|
|||
//m_context.Users.Add(a_user);
|
|||
|
|||
//var result = m_context.SaveChangesAsync();
|
|||
//result.Wait();
|
|||
//if(result.Result > 0)
|
|||
//{
|
|||
// return AuthEnums.Successful;
|
|||
//}
|
|||
//return AuthEnums.Error;
|
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Deletes a user account
|
|||
/// </summary>
|
|||
/// <exception cref="NotImplementedException"></exception>
|
|||
public void DeleteUser(int a_id) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
public List<Clientbusiness> GetClientbusiness(int a_clientId) |
|||
{ |
|||
return m_context.Clientbusinesses.Where(i => i.ClientId == a_clientId).ToList(); |
|||
} |
|||
|
|||
public Databasemap GetClientDB(int a_clientId) |
|||
{ |
|||
return m_context.Databasemaps.First(t => t.ClientId == a_clientId); |
|||
} |
|||
|
|||
public Contract? GetContract(int a_clientId, List<int> a_businessId) |
|||
{ |
|||
return m_context.Contracts.FirstOrDefault(c => c.ClientId == a_clientId && a_businessId.Contains(c.BusinessId!.Value) && c.EndDate >= DateTime.Now); |
|||
} |
|||
|
|||
public List<Siteaccesspermission> GetSiteaccesspermission(int a_clientId, int a_userId) |
|||
{ |
|||
return m_context.Siteaccesspermissions.Where(t => t.ClientId == a_clientId && t.UserId == a_userId).ToList(); |
|||
} |
|||
|
|||
private async Task<Userauth> GetUserAsync(string username, string password) |
|||
{ |
|||
//Todo have complete implementation after means of creating user is done
|
|||
//try
|
|||
//{
|
|||
// string pa = await m_context.Userauths.Where(u => u.Username == username).Select(u => u.Password).FirstAsync();
|
|||
// bool verified = BCrypt.Net.BCrypt.Verify(password, pa);
|
|||
// if (verified)
|
|||
// {
|
|||
|
|||
//TODO have a complete implementation
|
|||
return await m_context.Userauths.FirstAsync(u => u.Username == username && u.Passsword == password); |
|||
// }
|
|||
// else
|
|||
// {
|
|||
// return null;
|
|||
// }
|
|||
//}catch(Exception ex)
|
|||
//{
|
|||
// //possible is user not found
|
|||
// return null;
|
|||
//}
|
|||
} |
|||
} |
|||
} |
@ -0,0 +1,52 @@ |
|||
using Biskilog_Accounting.Server.POSModels; |
|||
using Biskilog_Accounting.Shared.ClientContractModels; |
|||
using Biskilog_Accounting.Shared.Enums; |
|||
using Biskilog_Accounting.Shared.Interfaces; |
|||
using Microsoft.EntityFrameworkCore; |
|||
using Microsoft.Extensions.Configuration; |
|||
|
|||
namespace Biskilog_Accounting.Server.Services |
|||
{ |
|||
public class ConnectionService : IConnectionService |
|||
{ |
|||
private readonly BiskilogContext m_context; |
|||
private readonly ITokenService m_tokenService; |
|||
private readonly IConfiguration m_configuration; |
|||
|
|||
public ConnectionService(BiskilogContext a_context, ITokenService a_tokenService, IConfiguration configuration) |
|||
{ |
|||
m_context = a_context; |
|||
m_tokenService = a_tokenService; |
|||
m_configuration = configuration; |
|||
} |
|||
/// <summary>
|
|||
/// Prepares and returns the connection string for a client using the specified database id
|
|||
/// </summary>
|
|||
/// <param name="a_databaseId">Specified database id to use</param>
|
|||
/// <returns></returns>
|
|||
public string GetClientConnectionString(int a_databaseId) |
|||
{ |
|||
Databasemap? dbMap = m_context.Databasemaps.Find(a_databaseId); |
|||
if (dbMap != null) |
|||
{ |
|||
string rawConString = m_configuration.GetConnectionString("PrivateConnection")!.ToString(); |
|||
return String.Format(rawConString, dbMap.Domain, dbMap.DbName); |
|||
} |
|||
return ConnectionEnums.ConnectionNotEstablished.ToString(); |
|||
} |
|||
/// <summary>
|
|||
/// Prepare the DB context from the specified connection string
|
|||
/// </summary>
|
|||
/// <param name="a_context"></param>
|
|||
/// <param name="a_connectionString"></param>
|
|||
/// <returns>A configured BiskAcdbContext</returns>
|
|||
public object PrepareDBContext(string a_connectionString) |
|||
{ |
|||
|
|||
DbContextOptionsBuilder<BiskAcdbContext> acdbContext = new DbContextOptionsBuilder<BiskAcdbContext>(); |
|||
acdbContext.UseMySql(a_connectionString, new MariaDbServerVersion(new Version())); |
|||
|
|||
return acdbContext; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,17 @@ |
|||
namespace Biskilog_Accounting.Shared.Enums |
|||
{ |
|||
public enum AuthEnums |
|||
{ |
|||
Registered, |
|||
AleadyLoggedin, |
|||
WrongPassword, |
|||
NotFound, |
|||
Found, |
|||
Expired, |
|||
Invalid, |
|||
Valid, |
|||
Successful, |
|||
Error |
|||
} |
|||
} |
|||
|
@ -0,0 +1,14 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Biskilog_Accounting.Shared.Enums |
|||
{ |
|||
public enum ConnectionEnums |
|||
{ |
|||
ConnectionEstablished, |
|||
ConnectionNotEstablished, |
|||
} |
|||
} |
@ -0,0 +1,24 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Biskilog_Accounting.Shared.Interfaces |
|||
{ |
|||
public interface IConnectionService |
|||
{ |
|||
/// <summary>
|
|||
/// Prepares and returns the connection string for a client using the specified database id
|
|||
/// </summary>
|
|||
/// <param name="a_databaseId">Specified database id to use</param>
|
|||
/// <returns></returns>
|
|||
string GetClientConnectionString(int a_databaseId); |
|||
/// <summary>
|
|||
/// Prepare the DB context from the specified connection string
|
|||
/// </summary>
|
|||
/// <param name="a_connectionString"></param>
|
|||
/// <returns>A configured BiskAcdbContext</returns>
|
|||
object PrepareDBContext(string a_connectionString); |
|||
} |
|||
} |
@ -0,0 +1,124 @@ |
|||
using Biskilog_Accounting.Shared.ClientContractModels; |
|||
using Biskilog_Accounting.Shared.Enums; |
|||
using Biskilog_Accounting.Shared.Interfaces; |
|||
using Microsoft.Extensions.Configuration; |
|||
using Microsoft.IdentityModel.Tokens; |
|||
using System.IdentityModel.Tokens.Jwt; |
|||
using System.Security.Claims; |
|||
using System.Text; |
|||
|
|||
namespace Biskilog_Accounting.ServiceRepo |
|||
{ |
|||
public class TokenService : ITokenService |
|||
{ |
|||
private IConfiguration m_configuration { get; } |
|||
public TokenService(IConfiguration a_configuration) |
|||
{ |
|||
m_configuration = a_configuration; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Validates a user access token
|
|||
/// </summary>
|
|||
/// <returns>AuthEnums.Valid if token is a valid and unexpired token</returns>
|
|||
public AuthEnums ValidateToken(string a_token) |
|||
{ |
|||
try |
|||
{ |
|||
string token = a_token.Substring(6).Trim(); |
|||
var handler = new JwtSecurityTokenHandler(); |
|||
JwtSecurityToken jwtToken = (JwtSecurityToken)handler.ReadToken(token); |
|||
|
|||
if (jwtToken.ValidFrom <= DateTime.Now && jwtToken.ValidTo > DateTime.Now) |
|||
return AuthEnums.Valid; |
|||
return AuthEnums.Expired; |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
Console.WriteLine(ex.Message); |
|||
return AuthEnums.Invalid; |
|||
} |
|||
} |
|||
/// <summary>
|
|||
/// Generates an access token based on the user
|
|||
/// </summary>
|
|||
/// <returns>A tokenized string</returns>
|
|||
public string GenerateToken(Userauth a_user, Contract a_clientContract, Databasemap a_database) |
|||
{ |
|||
try |
|||
{ |
|||
//create claims details based on the user information
|
|||
var claims = new[] { |
|||
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), |
|||
new Claim(JwtRegisteredClaimNames.Iat, DateTime.UtcNow.ToString()), |
|||
new Claim("ContractStart",a_clientContract.StartDate !.Value.ToString()), |
|||
new Claim("ContractEnd",a_clientContract.EndDate!.Value.ToString()), |
|||
new Claim("UserId", a_user.UserId.ToString()), |
|||
new Claim("Username", a_user.Username.ToString()), |
|||
new Claim("DbId",a_database.DbNo.ToString()), |
|||
new Claim("ClientId", a_user.ClientId.ToString()), |
|||
}; |
|||
|
|||
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(m_configuration["Jwt:Key"]!)); |
|||
|
|||
var signIn = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); |
|||
|
|||
var token = new JwtSecurityToken(m_configuration["Jwt:Issuer"], m_configuration["Jwt:Audience"], claims, expires: DateTime.UtcNow.AddDays(14), signingCredentials: signIn); |
|||
return $"{new JwtSecurityTokenHandler().WriteToken(token)}"; |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
Console.WriteLine(ex.Message); |
|||
return AuthEnums.Error.ToString(); |
|||
} |
|||
} |
|||
/// <summary>
|
|||
///Deserializes the token string if valid to return the specified user role id in the token string
|
|||
/// </summary>
|
|||
/// <param name="a_token"></param>
|
|||
/// <returns>RoleId</returns>
|
|||
public int? GetDatabaseIdFromToken(string a_token) |
|||
{ |
|||
if (ValidateToken(a_token) == AuthEnums.Valid) |
|||
{ |
|||
string token = a_token.Substring(6).Trim(); |
|||
var handler = new JwtSecurityTokenHandler(); |
|||
JwtSecurityToken jwtToken = (JwtSecurityToken)handler.ReadToken(token); |
|||
return int.Parse(jwtToken.Claims.First(claim => claim.Type == "DbId").Value); |
|||
} |
|||
return null; |
|||
} |
|||
/// <summary>
|
|||
///Deserializes the token string if valid to return the specified user id in the token string
|
|||
/// </summary>
|
|||
/// <param name="a_token"></param>
|
|||
/// <returns>UserId</returns>
|
|||
public int? GetUserIdFromToken(string a_token) |
|||
{ |
|||
if (ValidateToken(a_token) == AuthEnums.Valid) |
|||
{ |
|||
string token = a_token.Substring(6).Trim(); |
|||
var handler = new JwtSecurityTokenHandler(); |
|||
JwtSecurityToken jwtToken = (JwtSecurityToken)handler.ReadToken(token); |
|||
return int.Parse(jwtToken.Claims.First(claim => claim.Type == "UserId").Value); |
|||
} |
|||
return null; |
|||
} |
|||
/// <summary>
|
|||
///Deserializes the token string if valid to return the specified username in the token string
|
|||
/// </summary>
|
|||
/// <param name="a_token"></param>
|
|||
/// <returns>Username</returns>
|
|||
public string? GetUserNameFromToken(string a_token) |
|||
{ |
|||
if (ValidateToken(a_token) == AuthEnums.Valid) |
|||
{ |
|||
string token = a_token.Substring(6).Trim(); |
|||
var handler = new JwtSecurityTokenHandler(); |
|||
JwtSecurityToken jwtToken = (JwtSecurityToken)handler.ReadToken(token); |
|||
return jwtToken.Claims.First(claim => claim.Type == "Username").Value; |
|||
} |
|||
return null; |
|||
} |
|||
} |
|||
} |
Loading…
Reference in new issue