using Biskilog_Accounting.Shared.ClientContractModels ;
using Biskilog_Accounting.Shared.Enums ;
using Biskilog_Accounting.Shared.Interfaces ;
using Blazored.LocalStorage ;
using Blazored.SessionStorage ;
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 ; }
private readonly ISessionStorageService m_sessionStorage ;
private readonly ILocalStorageService m_localStorage ;
public TokenService ( IConfiguration a_configuration , ISessionStorageService a_sessionStorage = null , ILocalStorageService a_localStorage = null )
{
m_configuration = a_configuration ;
m_sessionStorage = a_sessionStorage ;
m_localStorage = a_localStorage ;
}
/// <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 )
{
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 , List < string > a_business , bool a_comparison )
{
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 ( "ComparisonMode" , a_comparison . ToString ( ) ) ,
new Claim ( "BranchId" , a_business [ 0 ] . ToString ( ) ) ,
new Claim ( "BranchAccess" , string . Join ( ", " , a_business . ToArray ( ) ) ) ,
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 ( 1 4 ) , 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 ;
}
/// <summary>
///Deserializes the token string if valid to return the specified branchId in the token string
/// </summary>
/// <param name="a_token"></param>
/// <returns>Username</returns>
public string? GetBaseBranch ( 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 = = "BranchId" ) . Value ;
}
return null ;
}
public bool? GetComparison ( 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 bool . Parse ( jwtToken . Claims . First ( claim = > claim . Type = = "ComparisonMode" ) . Value ) ;
}
return null ;
}
/// <summary>
///Deserializes the token string if valid to return the specified list of branches a user has access to in the token string
/// </summary>
/// <param name="a_token"></param>
/// <returns>Username</returns>
public string? GetAllBranch ( 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 = = "BranchAccess" ) . Value ;
}
return null ;
}
/// <summary>
/// Return a specified list of branches a user has access if comparison mode is set otherwise returns only the
/// active branch on the list
/// </summary>
/// <param name="a_token"></param>
/// <returns></returns>
public IEnumerable < string > BranchIds ( string a_token )
{
List < string > branchIds = new List < string > ( ) ;
if ( ValidateToken ( a_token ) = = AuthEnums . Valid )
{
bool comparison = GetComparison ( a_token ) ! . Value ;
if ( comparison )
{
string? branches = GetAllBranch ( a_token ) ;
if ( branches ! = null )
{
string [ ] branchArray = branches ! . Split ( ) ;
branchIds . AddRange ( branchArray ) ;
}
}
else
{
string? baseBranch = GetBaseBranch ( a_token ) ;
branchIds . Add ( baseBranch ! ) ;
}
}
return branchIds . AsEnumerable ( ) ;
}
public async Task SetToken ( string a_token , bool a_remember )
{
if ( a_remember )
{
await m_localStorage . SetItemAsStringAsync ( "token" , $"Bearer {a_token}" ) ;
}
else
{
await m_sessionStorage . SetItemAsStringAsync ( "token" , $"Bearer {a_token}" ) ;
}
}
public async Task < string > GetToken ( )
{
string token = await m_localStorage . GetItemAsStringAsync ( "token" ) ;
if ( String . IsNullOrEmpty ( token ) )
{
token = await m_sessionStorage . GetItemAsStringAsync ( "token" ) ;
}
return token ;
}
public async Task ClearToken ( )
{
await m_localStorage . ClearAsync ( ) ;
await m_sessionStorage . ClearAsync ( ) ;
}
public async Task < bool > IsTokenSet ( )
{
return await m_localStorage . ContainKeyAsync ( "token" ) | | await m_sessionStorage . ContainKeyAsync ( "token" ) ;
}
}
}