Files
2026-03-22 14:08:25 +03:30

742 lines
21 KiB
C#

using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using xCommons.Extensions;
using xCommons.Helpers;
using xExceptions.Constants;
using xIdentityModels;
using xIdentityModels.Constants;
using xIdentityModels.Extensions;
using xIdentityModels.Models;
using xIdentityModels.Navigations;
namespace xIds.Providers
{
public partial class XIdentityManager
{
//
#region Token Actions ...
/// <summary>
/// Check a Token Entity Exists or not
/// </summary>
/// <param name="device">an instance of <see>XDevice</see></param>
/// <param name="type">specifies Action Step by a member of <see>XAction</see></param>
/// <returns>a boolean value</returns>
private async Task<bool> IsTokenExistsByDeviceAndType(
XDevice device,
XAction type
)
{
//
ValidationProvider.NotNull(device);
//
var isExists = false;
var enumerator = DbContext.Tokens.AsAsyncEnumerable();
await
foreach (var token in enumerator)
{
//
if (token.Type == type &&
token.Device.IsSameAs(device))
{
isExists = true;
break;
}
}
//
return isExists;
}
/// <summary>
/// Check a Token Entity Exists or not
/// </summary>
/// <param name="userSelectByParam">specified user's identifier</param>
/// <param name="type">specifies Action Step by a member of <see>XAction</see></param>
/// <returns>a boolean value</returns>
private async Task<bool> IsTokenExistsByUserAndType(
string userSelectByParam,
XAction type
)
{
//
ValidationProvider.NotEmpty(userSelectByParam);
//
var isExists = false;
var tokensEnumerator = DbContext.Tokens.AsAsyncEnumerable();
await
foreach (var token in tokensEnumerator)
{
//
if (token.Type == type &&
token.UserSelectByParam
.ToNormalString() == userSelectByParam
.ToNormalString())
{
//
isExists = true;
break;
}
}
//
return isExists;
}
/// <summary>
/// Check a Token Entity Exists or not
/// </summary>
/// <param name="token">represent specified action token</param>
/// <returns>a boolean value</returns>
private async Task<bool> IsTokenExistsByToken(
string token
)
{
//
var result = await DbContext.Tokens
.AnyAsync(xt => xt.Token == token);
//
return result;
}
/// <summary>
/// Check a Token Entity Exists or not
/// </summary>
/// <param name="hash">represent specified action token hash</param>
/// <returns>a boolean value</returns>
private async Task<bool> IsTokenExistsByHash(
string hash
)
{
//
var result = await DbContext.Tokens
.AnyAsync(xt => xt.Hash == hash);
//
return result;
}
/// <summary>
/// Check a Token Entity Exists or not
/// </summary>
/// <param name="item">an instance of <see>XToken</see></param>
/// <returns>a boolean value</returns>
private async Task<bool> IsTokenExistsByToken(
XToken item
)
{
//
var result = false;
var tokenEnumerator = DbContext.Tokens
.AsAsyncEnumerable();
await
foreach (var token in tokenEnumerator)
{
//
if (token.Hash == item.Hash &&
token.Token == item.Token &&
token.Type == item.Type &&
token.UserSelectByParam
.ToNormalString() == item.UserSelectByParam
.ToNormalString() &&
token.Device.IsSameAs(item.Device))
{
//
result = true;
break;
}
}
//
return result;
}
/// <summary>
/// Check a Token Entity Exists or not
/// </summary>
/// <param name="id">specifies token id</param>
/// <returns>a boolean value</returns>
private async Task<bool> IsTokenExistsById(
int id
)
{
return await DbContext.Tokens.AnyAsync(t => t.Id == id);
}
/// <summary>
/// Retrieve Token Entity
/// </summary>
/// <param name="device">an instance of <see>XDevice</see></param>
/// <param name="type">specifies Action Step by a member of <see>XAction</see></param>
/// <returns>an instance of <see>XToken</see></returns>
private async Task<XToken> GetTokenByDeviceAndType(
XDevice device,
XAction type
)
{
//
var isExists = await IsTokenExistsByDeviceAndType(device, type);
if (!isExists)
{
return null;
}
//
XToken item = null;
var enumerator = DbContext.Tokens.AsAsyncEnumerable();
await
foreach (var token in enumerator)
{
//
if (token.Type == type &&
token.Device.IsSameAs(device))
{
//
item = token;
break;
}
}
//
return item;
}
/// <summary>
/// Retrieve Token Entity
/// </summary>
/// <param name="userSelectByParam">specified user's identifier</param>
/// <param name="type">specifies Action Step by a member of <see>XAction</see></param>
/// <returns>an instance of <see>XToken</see></returns>
private async Task<XToken> GetTokenByUserAndType(
string userSelectByParam,
XAction type
)
{
//
var isExists = await IsTokenExistsByUserAndType(userSelectByParam, type);
if (!isExists)
{
return null;
}
//
XToken item = null;
var enumerator = DbContext.Tokens.AsAsyncEnumerable();
await
foreach (var token in enumerator)
{
//
if (token.Type == type &&
token.UserSelectByParam
.ToNormalString() == userSelectByParam
.ToNormalString())
{
//
item = token;
break;
}
}
//
return item;
}
/// <summary>
/// Retrieve a Token Entity
/// </summary>
/// <param name="token">represent specified action token</param>
/// <returns>an instance of <see>XToken</see></returns>
private async Task<XToken> GetTokenByToken(
string token
)
{
//
var isExists = await IsTokenExistsByToken(token);
if (!isExists)
{
return null;
}
//
var result = await DbContext.Tokens
.FirstOrDefaultAsync(xt => xt.Token == token);
//
return result;
}
/// <summary>
/// Retrieve Related Hash to a Token
/// </summary>
/// <param name="token">represent specified action token</param>
/// <returns>hash string</returns>
private async Task<string> GetRelatedHashByToken(
string token
)
{
//
var item = await GetTokenByToken(token);
if (item == null)
{
return null;
}
//
return item.Hash;
}
/// <summary>
/// Retrieve a Token Entity
/// </summary>
/// <param name="hash">represent specified action token hash</param>
/// <returns>an instance of <see>XToken</see></returns>
private async Task<XToken> GetTokenByHash(
string hash
)
{
//
// Validate Args ...
ValidationProvider.NotEmpty(hash);
//
var isExists = await IsTokenExistsByHash(hash);
if (!isExists)
{
return null;
}
//
var item = await DbContext.Tokens
.FirstOrDefaultAsync(t => t.Hash == hash);
//
return item;
}
/// <summary>
/// Retrieve Related Token to a Hash string
/// </summary>
/// <param name="hash">represent specified action token hash</param>
/// <returns>token string</returns>
private async Task<string> GetRelatedTokenByHash(
string hash
)
{
//
var item = await GetTokenByHash(hash);
if (item == null)
{
return null;
}
//
return item.Token;
}
/// <summary>
/// Retrieve a Token Expiration Date
/// </summary>
/// <param name="token">represent specified action token</param>
/// <returns>an instance of <see>DateTime</see></returns>
private DateTime GetTokenExpirationDate(
string token
)
{
//
ValidationProvider.NotEmpty(token);
//
var result = IdentityHelper.GetTokenExpirationDate(token);
//
return result;
}
/// <summary>
/// Remove a Token Entity
/// </summary>
/// <param name="token">represent specified action token</param>
/// <returns></returns>
private async Task RemoveTokenByToken(
string token
)
{
//
// Validate Args ...
ValidationProvider.NotEmpty(token);
//
var isExists = await IsTokenExistsByToken(token);
if (!isExists)
{
return;
}
//
var item = await GetTokenByToken(token);
if (item == null)
{
return;
}
//
DbContext.Tokens.Remove(item);
await DbContext.SaveChangesAsync();
}
/// <summary>
/// Remove a Token Entity
/// </summary>
/// <param name="hash">represent specified action token hash</param>
/// <returns></returns>
private async Task RemoveTokenByHash(
string hash
)
{
//
// Validate Args ...
ValidationProvider.NotEmpty(hash);
//
var isExists = await IsTokenExistsByHash(hash);
if (!isExists)
{
return;
}
//
var item = await GetTokenByHash(hash);
if (item == null)
{
return;
}
//
DbContext.Tokens.Remove(item);
await DbContext.SaveChangesAsync();
}
/// <summary>
/// Remove a Token Entity
/// </summary>
/// <param name="device">an instance of <see>XDevice</see></param>
/// <returns></returns>
private async Task RemoveTokenByDevice(
XDevice device
)
{
//
// Validate Args ...
ValidationProvider.NotNull(device);
//
XToken items = null;
var enumerator = DbContext.Tokens.AsAsyncEnumerable();
await
foreach (var token in enumerator)
{
//
if (token.Device.IsSameAs(device))
{
//
items = token;
break;
}
}
//
if (!items.IsNull())
{
DbContext.Tokens.RemoveRange(items);
await DbContext.SaveChangesAsync();
}
}
/// <summary>
/// add a token Entity
/// </summary>
/// <param name="item">an instance of <see>XToken</see></param>
/// <returns>an instance of <see>XToken</see></returns>
private async Task<XToken> AddTokenAsync(
XToken item
)
{
//
var isExist = await IsTokenExistsByToken(item);
if (isExist)
{
return await GetTokenByHash(item.Hash);
}
//
var entry = await DbContext.Tokens.AddAsync(item);
await DbContext.SaveChangesAsync();
//
return entry.Entity;
}
/// <summary>
/// Hash a Request Token
/// </summary>
/// <param name="request">an instance of <see>XActionRequestToken</see></param>
/// <param name="forceNotNullUserSelectByParam"></param>
/// <param name="forceDeviceNotNull"></param>
/// <returns>an instance of <see>XToken</see></returns>
private async Task<XToken> HashRequest(
XActionRequestToken request,
bool forceNotNullUserSelectByParam = true,
bool forceDeviceNotNull = true
)
{
//
// Validate Args ...
var secretKey = Configuration.IdentitySecretKey;
ValidationProvider.NotNull(request);
ValidationProvider.NotEmpty(secretKey);
//
ValidateActionRequest(request);
//
var type = request.Action;
var device = request.Context.Device;
var tokenObject = ToSecurityToken(request);
var tokenString = ToTokenString(tokenObject);
var tokenHash = ToHash(tokenString);
var userSelectByParam = GetUserSelectByParam(request, forceNotNullUserSelectByParam);
//
if (forceNotNullUserSelectByParam)
{
ValidationProvider.NotEmpty(userSelectByParam);
}
//
ValidationProvider.NotEmpty(tokenString, tokenHash);
//
if (forceDeviceNotNull)
{
ValidationProvider.NotNull(device);
}
//
ValidationProvider.NotNull(tokenObject);
//
var xToken = new XToken
{
Type = type,
Device = device,
Hash = tokenHash,
Token = tokenString,
UserSelectByParam = userSelectByParam
};
//
var addedToken = await AddTokenAsync(xToken);
//
return addedToken;
}
/// <summary>
/// Generate Token Hash string
/// </summary>
/// <param name="token">represent specified action token</param>
/// <param name="checkValidation">check token validation parameters, default is true</param>
/// <returns>hash string</returns>
private string ToHash(
string token,
bool checkValidation = true
)
{
//
ValidationProvider.NotEmpty(token);
//
if (checkValidation)
{
ValidateToken(token);
}
//
var result = token.ToMd5String().ToNormalString();
//
return result;
}
/// <summary>
/// Generate Token string
/// </summary>
/// <param name="token">represent specified action token</param>
/// <returns>token string</returns>
private string ToTokenString(
SecurityToken token
)
{
//
ValidationProvider.NotNull(token, IdentityHelper);
//
var result = IdentityHelper.ToTokenString(token);
//
return result;
}
/// <summary>
/// Generate Token string
/// </summary>
/// <param name="token">represent specified action token</param>
/// <returns>token string</returns>
private string ToTokenString(
JwtSecurityToken token
)
{
//
ValidationProvider.NotNull(token, IdentityHelper);
//
var result = IdentityHelper.ToTokenString(token);
//
return result;
}
/// <summary>
/// Generate Security Token
/// </summary>
/// <param name="token">represent specified action token</param>
/// <returns>an instance of <see>SecurityToken</see></returns>
private SecurityToken ToSecurityToken(
string token
)
{
//
ValidationProvider.NotEmpty(token);
//
var result = IdentityHelper.ToSecurityToken(token);
//
return result;
}
/// <summary>
/// Generate Security Token
/// </summary>
/// <param name="request">an instance of <see>XActionRequestToken</see></param>
/// <returns>an instance of <see>SecurityToken</see></returns>
private SecurityToken ToSecurityToken(
XActionRequestToken request
)
{
//
ValidationProvider.NotNull(request);
//
ValidateActionRequest(request);
//
var result = IdentityHelper.ToSecurityToken(request);
if (result == null)
{
XException.InvalidToken.Throw();
}
//
return result;
}
/// <summary>
/// Cleanup all exists tokens related to specified User
/// </summary>
/// <param name="userSelectByParam">specified user's identifier</param>
/// <returns></returns>
private async Task HandleRemoveExistsTokens(
string userSelectByParam
)
{
//
// Validate Args ...
ValidationProvider.NotEmpty(userSelectByParam);
//
var xTokens = new List<XToken>();
var xTokenEnumerator = DbContext.Tokens.AsAsyncEnumerable();
await
foreach (var xToken in xTokenEnumerator)
{
//
if (xToken.UserSelectByParam == userSelectByParam &&
ObjectHelper.ToEnumerableValues<XAction>().Contains(xToken.Type))
{
xTokens.Add(xToken);
}
}
//
if (xTokens.HasChild())
{
DbContext.Tokens.RemoveRange(xTokens);
await DbContext.SaveChangesAsync();
}
}
/// <summary>
/// Cleanup all tokens related to specified User
/// </summary>
/// <param name="userSelectByParams">a collection of user identifiers</param>
/// <returns></returns>
private async Task HandleCleanUserTokens(
ICollection<string> userSelectByParams
)
{
//
// Validate Args ...
if (!userSelectByParams.HasChild())
{
return;
}
//
foreach (var userSelectByParam in userSelectByParams)
{
await HandleRemoveExistsTokens(userSelectByParam);
}
}
/// <summary>
/// Cleanup all tokens related to specified User
/// </summary>
/// <param name="user">an instance of <see>XUser</see></param>
/// <returns></returns>
private async Task HandleCleanUserTokens(
XUser user
)
{
//
if (user == null)
{
return;
}
//
var userSelectByParams = GenerateUserSelectByParams(user);
//
await HandleCleanUserTokens(userSelectByParams);
}
#endregion
}
}