188 lines
6.9 KiB
C#
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; }
|
|
}
|
|
} |