MyBookmark/Modules.User.Application/UserContext.cs
2024-11-27 03:22:03 +03:00

188 lines
6.9 KiB
C#

using MediatR;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using Modules.User.Application.Models;
using Modules.User.Application.Queries;
using Modules.User.Application.Settings;
using MyCSharp.HttpUserAgentParser.Providers;
using System.Net.Http;
using System.Net.Http.Json;
using System.Security.Claims;
using System.Text;
namespace Modules.User.Application;
public class UserContext
{
private readonly IMediator _mediator;
//private readonly IHttpContextAccessor _httpContextAccessor;
private readonly JwtSettings _jwtSettings;
private Models.User? _user;
private string? _userAgent;
private string? _refreshToken;
private string? _clientIp;
private readonly IHttpClientFactory _httpClientFactory;
private readonly IHttpUserAgentParserProvider _userAgentParser;
//public UserContext(IOptionsMonitor<JwtSettings> jwtSettingsOptions, IMediator mediator, IHttpContextAccessor httpContextAccessor, IConfiguration configuration)
//public UserContext(IOptionsMonitor<JwtSettings> jwtSettingsOptions, IMediator mediator, IHttpContextAccessor httpContextAccessor, IHttpClientFactory httpClientFactory)
public UserContext(IOptionsMonitor<JwtSettings> jwtSettingsOptions, IMediator mediator, IHttpClientFactory httpClientFactory,
IHttpUserAgentParserProvider userAgentParser)
{
_mediator = mediator;
//_httpContextAccessor = httpContextAccessor;
_userAgentParser = userAgentParser;
_jwtSettings = jwtSettingsOptions.CurrentValue;
_httpClientFactory = httpClientFactory;
}
public JwtSettings GetJwtSettings() => _jwtSettings;
internal void SetUserInfo(HttpContext httpContext, CancellationToken cancellationToken = default)
{
if (_user == null || !_user.IsAuthenticated)
{
if (Guid.TryParse(httpContext.User.FindFirstValue(Constants.AccountIdKey), out Guid accountId))
_user = new Models.User
{
AccountId = accountId,
SessionId = Guid.TryParse(httpContext.User.FindFirstValue(Constants.SessionIdKey), out Guid sessionId) ? sessionId : null,
};
else _user = new Models.User();
//await RetrieveUserInfo(_user);
if (!_user.IsAuthenticated) { }
}
}
public async Task<Models.User> GetUserInfo(CancellationToken cancellationToken = default)
{
if (_user == null)
{
return _user = new Models.User();
}
if (!_user.IsAuthenticated)
{
if (_user.AccountId.HasValue)
_user = await _mediator.Send(new GetUserQuery
{
AccountId = _user.AccountId.Value,
SessionId = _user.SessionId,
}, cancellationToken);
else _user = new Models.User();
if (!_user.IsAuthenticated) { }
}
return _user;
}
//private async Task RetrieveUserInfo(Models.User user)
//{
// var ip = GetClientIp();
// var ipAddressWithoutPort = ip?.Split(':')[0];
// var location = await GetLocation(ipAddressWithoutPort);
// var clientInfo = new ClientInfo
// {
// Ip = !string.IsNullOrWhiteSpace(ipAddressWithoutPort) ? ipAddressWithoutPort : null,
// UserAgent = _httpContextAccessor.HttpContext?.Request.Headers.UserAgent,
// Location = location,
// };
// user.ClientInfo = clientInfo;
//}
internal void SetUserAgent(HttpContext httpContext) =>
_userAgent = httpContext.Request.Headers.UserAgent;
//internal string? GetUserAgent() => _httpContextAccessor.HttpContext?.Request.Headers.UserAgent;
internal string? GetUserAgent()
{
if (string.IsNullOrWhiteSpace(_userAgent))
{
return null;
}
var parsedUseragent = _userAgentParser.Parse(_userAgent.ToString());
var sb = new StringBuilder();
if (!string.IsNullOrWhiteSpace(parsedUseragent.MobileDeviceType))
{
sb.Append(string.Concat("Mobile device: ", parsedUseragent.MobileDeviceType, ", "));
}
sb.Append(string.Concat(parsedUseragent.Name, " v", parsedUseragent.Version));
if (!string.IsNullOrWhiteSpace(parsedUseragent.Platform?.Name))
{
sb.Append(string.Concat(", ", parsedUseragent.Platform.Value.Name));
}
return sb.ToString();
}
internal void SetRefreshToken(HttpContext httpContext)
{
if (httpContext.Request.Cookies.TryGetValue(TokenGenerator.RefreshTokenName, out string? refreshToken))
{
_refreshToken = refreshToken;
}
else
{
_refreshToken = null;
}
}
//internal string? GetRefreshToken(string refreshTokenName) => _httpContextAccessor.HttpContext?.Request
internal string? GetRefreshToken() => _refreshToken;
internal void SetClientIp(HttpContext httpContext)
{
var ip = httpContext.GetServerVariable("HTTP_X_FORWARDED_FOR");
if (string.IsNullOrWhiteSpace(ip)) ip = httpContext.Request.Headers["CF-CONNECTING-IP"];
if (string.IsNullOrWhiteSpace(ip)) ip = httpContext.Connection.RemoteIpAddress?.ToString();
_clientIp = ip?.Trim();
}
private string? GetClientIp() => _clientIp;
//вынести в сервис
internal async Task<Location?> GetLocation(string? ip)
{
if (string.IsNullOrWhiteSpace(ip))
{
ip = GetClientIp();
if (string.IsNullOrWhiteSpace(ip))
{
return null;
}
}
//var client = new HttpClient() { BaseAddress = new Uri("http://ip-api.com") };
var client = _httpClientFactory.CreateClient();
try
{
//var response = await client.GetFromJsonAsync<IpApiResponse>($"/json/{ip}");
var response = await client.GetFromJsonAsync<IpApiResponse>($"http://ip-api.com/json/{ip}");
return response == null || (!response.lat.HasValue || !response.lon.HasValue) ? null : new Location
{
//Latitude = response.lat.Value,
//Longutude = response.lon.Value,
Country = response.country,
Region = response.regionName,
};
}
catch { return null; }
}
public sealed class IpApiResponse
{
public string? status { get; set; }
public string? continent { get; set; }
public string? country { get; set; }
public string? regionName { get; set; }
public string? city { get; set; }
public string? district { get; set; }
public string? zip { get; set; }
public double? lat { get; set; }
public double? lon { get; set; }
public string? isp { get; set; }
public string? query { get; set; }
}
}