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 jwtSettingsOptions, IMediator mediator, IHttpContextAccessor httpContextAccessor, IConfiguration configuration) //public UserContext(IOptionsMonitor jwtSettingsOptions, IMediator mediator, IHttpContextAccessor httpContextAccessor, IHttpClientFactory httpClientFactory) public UserContext(IOptionsMonitor 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 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 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($"/json/{ip}"); var response = await client.GetFromJsonAsync($"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; } } }