295 lines
7.6 KiB
C#
295 lines
7.6 KiB
C#
|
|
using Microsoft.AspNetCore.Http;
|
|||
|
|
using Microsoft.Extensions.Logging;
|
|||
|
|
using Microsoft.Extensions.Primitives;
|
|||
|
|
using System;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using System.IO;
|
|||
|
|
using System.IO.Compression;
|
|||
|
|
using System.Linq;
|
|||
|
|
using System.Net.Http.Headers;
|
|||
|
|
using System.Security.Claims;
|
|||
|
|
using System.Text;
|
|||
|
|
using System.Threading.Tasks;
|
|||
|
|
|
|||
|
|
namespace OnlineSalesAutoCrop.CoreAPI
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
///
|
|||
|
|
/// </summary>
|
|||
|
|
public static class ExtensionMethods
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
///
|
|||
|
|
/// </summary>
|
|||
|
|
/// <typeparam name="T"></typeparam>
|
|||
|
|
/// <param name="principal"></param>
|
|||
|
|
/// <param name="type"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
public static T GetClaimValue<T>(this ClaimsPrincipal principal, string type)
|
|||
|
|
{
|
|||
|
|
if (principal?.Identity == null || !principal.Identity.IsAuthenticated)
|
|||
|
|
return typeof(T) == typeof(string) ? ((T)Convert.ChangeType(string.Empty, typeof(T))) : default;
|
|||
|
|
|
|||
|
|
Claim claim = principal.Claims.SingleOrDefault(p => p.Type == type);
|
|||
|
|
if (string.IsNullOrEmpty(claim?.Value))
|
|||
|
|
return typeof(T) == typeof(string) ? ((T)Convert.ChangeType(string.Empty, typeof(T))) : default;
|
|||
|
|
|
|||
|
|
return (T)Convert.ChangeType(claim.Value, typeof(T));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
///
|
|||
|
|
/// </summary>
|
|||
|
|
/// <typeparam name="T"></typeparam>
|
|||
|
|
/// <param name="session"></param>
|
|||
|
|
/// <param name="key"></param>
|
|||
|
|
/// <param name="value"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
public static async Task<bool> SetModulesToSession<T>(this ISession session, string key, T value)
|
|||
|
|
{
|
|||
|
|
ArgumentNullException.ThrowIfNull(session);
|
|||
|
|
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
string jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(value);
|
|||
|
|
session.SetString(key: key, value: jsonString);
|
|||
|
|
await session.CommitAsync();
|
|||
|
|
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
catch
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
///
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="context"></param>
|
|||
|
|
/// <param name="moduleId"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
public static async Task<bool> IsPermitted(this HttpContext context, string moduleId)
|
|||
|
|
{
|
|||
|
|
if (context?.Session is null)
|
|||
|
|
return false;
|
|||
|
|
|
|||
|
|
string key = context.GetAuthenticationToken();
|
|||
|
|
if (string.IsNullOrEmpty(key))
|
|||
|
|
return false;
|
|||
|
|
|
|||
|
|
await context.Session.LoadAsync();
|
|||
|
|
string moduleIds = context.Session.GetString(key: key);
|
|||
|
|
if (string.IsNullOrEmpty(moduleIds))
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
List<string> value = Newtonsoft.Json.JsonConvert.DeserializeObject<List<string>>(moduleIds);
|
|||
|
|
return value.Contains(moduleId);
|
|||
|
|
}
|
|||
|
|
catch
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
///
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="value"></param>
|
|||
|
|
/// <param name="moduleId"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
public static async Task<bool> IsPermitted(this List<string> value, string moduleId)
|
|||
|
|
{
|
|||
|
|
if (value?.Count <= 0)
|
|||
|
|
return false;
|
|||
|
|
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
return value.Contains(moduleId);
|
|||
|
|
}
|
|||
|
|
catch
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
///
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="context"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
public static bool IsSessionExpired(this HttpContext context)
|
|||
|
|
{
|
|||
|
|
if (context?.Session is null)
|
|||
|
|
return true;
|
|||
|
|
|
|||
|
|
string key = context.GetAuthenticationToken();
|
|||
|
|
if (string.IsNullOrEmpty(key))
|
|||
|
|
return true;
|
|||
|
|
|
|||
|
|
string moduleIds = context.Session.GetString(key: key);
|
|||
|
|
if (string.IsNullOrEmpty(moduleIds))
|
|||
|
|
return true;
|
|||
|
|
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
///
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="context"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
public static async Task<bool> ClearSessionAsync(this HttpContext context)
|
|||
|
|
{
|
|||
|
|
if (context?.Session is null)
|
|||
|
|
return false;
|
|||
|
|
|
|||
|
|
context.Session.Clear();
|
|||
|
|
await context.Session.CommitAsync();
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
///
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="context"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
public static string GetAuthenticationToken(this HttpContext context)
|
|||
|
|
{
|
|||
|
|
if (context == null)
|
|||
|
|
{
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Attempt to retrieve the "Authorization" header
|
|||
|
|
if (context.Request.Headers.TryGetValue("Authorization", out StringValues authHeaderValues))
|
|||
|
|
{
|
|||
|
|
var authHeader = authHeaderValues.FirstOrDefault();
|
|||
|
|
// Parse the header using AuthenticationHeaderValue
|
|||
|
|
if (authHeader != null && AuthenticationHeaderValue.TryParse(authHeader, out AuthenticationHeaderValue authHeaderValue))
|
|||
|
|
{
|
|||
|
|
// For Bearer tokens, the scheme is "Bearer" and the parameter is the token
|
|||
|
|
if (authHeaderValue.Scheme.Equals("Bearer", StringComparison.OrdinalIgnoreCase))
|
|||
|
|
{
|
|||
|
|
return authHeaderValue.Parameter;
|
|||
|
|
}
|
|||
|
|
// For Basic authentication, the scheme is "Basic" and the parameter is base64 encoded credentials
|
|||
|
|
else if (authHeaderValue.Scheme.Equals("Basic", StringComparison.OrdinalIgnoreCase))
|
|||
|
|
{
|
|||
|
|
// You would then typically decode this parameter to get username and password
|
|||
|
|
return authHeaderValue.Parameter;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
///
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="context"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
public static string GetIpAddress(this HttpContext context)
|
|||
|
|
{
|
|||
|
|
string ip = GetHeaderValueAs<string>(context: context, headerName: "X-Forwarded-For").SplitCsv().FirstOrDefault();
|
|||
|
|
if (string.IsNullOrEmpty(ip) && context?.Connection?.RemoteIpAddress != null)
|
|||
|
|
{
|
|||
|
|
ip = context?.Connection?.RemoteIpAddress.ToString();
|
|||
|
|
if (string.IsNullOrEmpty(ip))
|
|||
|
|
{
|
|||
|
|
ip = GetHeaderValueAs<string>(context: context, headerName: "REMOTE_ADDR");
|
|||
|
|
if (string.IsNullOrEmpty(ip))
|
|||
|
|
ip = context.Request?.Host.Value;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return ip ?? string.Empty;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
///
|
|||
|
|
/// </summary>
|
|||
|
|
/// <typeparam name="T"></typeparam>
|
|||
|
|
/// <param name="context"></param>
|
|||
|
|
/// <param name="headerName"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
private static T GetHeaderValueAs<T>(HttpContext context, string headerName)
|
|||
|
|
{
|
|||
|
|
if (context.Request?.Headers?.TryGetValue(headerName, out StringValues values) ?? false)
|
|||
|
|
{
|
|||
|
|
string rawValues = values.ToString();
|
|||
|
|
|
|||
|
|
if (!string.IsNullOrEmpty(rawValues))
|
|||
|
|
return (T)Convert.ChangeType(values.ToString(), typeof(T));
|
|||
|
|
}
|
|||
|
|
return default;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
///
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="csvList"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
private static List<string> SplitCsv(this string csvList)
|
|||
|
|
{
|
|||
|
|
if (string.IsNullOrWhiteSpace(csvList))
|
|||
|
|
return [];
|
|||
|
|
|
|||
|
|
return [.. csvList.TrimEnd(',').Split(',').AsEnumerable().Select(s => s.Trim())];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
///
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="textToCompress"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
public static string CompressString(this string textToCompress)
|
|||
|
|
{
|
|||
|
|
byte[] bytes = Encoding.UTF8.GetBytes(textToCompress);
|
|||
|
|
using var ms = new MemoryStream();
|
|||
|
|
using (BrotliStream brotli = new(ms, CompressionLevel.Optimal))
|
|||
|
|
{
|
|||
|
|
brotli.Write(bytes, 0, bytes.Length);
|
|||
|
|
}
|
|||
|
|
return Convert.ToBase64String(ms.ToArray());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
///
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="textToDecompress"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
public static string DecompressString(this string textToDecompress)
|
|||
|
|
{
|
|||
|
|
byte[] bytes = Convert.FromBase64String(textToDecompress);
|
|||
|
|
using var ms = new MemoryStream(bytes);
|
|||
|
|
using var Brotli = new BrotliStream(ms, CompressionMode.Decompress);
|
|||
|
|
using var sr = new StreamReader(Brotli);
|
|||
|
|
return sr.ReadToEnd();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
///
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="textToDecompress"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
public static List<string> DecompressModuleIds(this string textToDecompress)
|
|||
|
|
{
|
|||
|
|
return textToDecompress.DecompressString().SplitCsv();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
///
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="logger"></param>
|
|||
|
|
/// <param name="exception"></param>
|
|||
|
|
public static void LogError(this ILogger logger, Exception exception)
|
|||
|
|
{
|
|||
|
|
logger.LogError(exception: exception, message: string.Empty);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|