first commit
This commit is contained in:
@@ -0,0 +1,689 @@
|
||||
using Fitness_core_BE.DTOs.Auth;
|
||||
using Fitness_core_BE.Helpers;
|
||||
using Fitness_core_BE.Infra.UoW;
|
||||
using Fitness_core_BE.Interfaces;
|
||||
using Fitness_core_BE.Interfaces.Services;
|
||||
using Fitness_core_BE.Models;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Fitness_core_BE.Services.Auth
|
||||
{
|
||||
public class AuthService(IHttpClientFactory httpClientFactory, ICustomerRepository customerRepository, IUnitOfWork unitOfWork, IConfiguration configuration) : IAuthService
|
||||
{
|
||||
|
||||
private readonly HttpClient _httpClient = httpClientFactory.CreateClient();
|
||||
private readonly ICustomerRepository _cusRepo = customerRepository;
|
||||
private readonly IUnitOfWork _UoW = unitOfWork;
|
||||
private readonly string _baseUrl = configuration["AuthService:BaseUrl"] ?? "http://127.0.0.1:5602";
|
||||
|
||||
private string AuthAltTargetUrl => _baseUrl + "/api/alt";
|
||||
private string AuthUserTargetUrl => _baseUrl + "/api/user";
|
||||
private string AuthRecoveryTargetUrl => _baseUrl + "/api/recovery";
|
||||
|
||||
|
||||
|
||||
public async Task<AuthResponse> SendOtp(object payload, HttpContext httpContext)
|
||||
{
|
||||
var targetUrl = AuthAltTargetUrl;
|
||||
var request = new
|
||||
{
|
||||
functionName = "sendOtp",
|
||||
payload,
|
||||
reference = "send-otp"
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(request);
|
||||
|
||||
var forwardRequest = new HttpRequestMessage(HttpMethod.Post, targetUrl)
|
||||
{
|
||||
Content = new StringContent(json, Encoding.UTF8, "application/json")
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
var response = await _httpClient.SendAsync(forwardRequest);
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
var authResponse = JsonSerializer.Deserialize<AuthResponse>(responseContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||
|
||||
return authResponse ?? new AuthResponse { StatusCode = 500, Success = false, Message = "Empty response from auth service", Data = null };
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new AuthResponse { StatusCode = 500, Success = false, Message = $"Error communicating with auth service: {ex.Message}", Data = null };
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<AuthResponse> LoginUser(object payload, HttpContext httpContext)
|
||||
{
|
||||
// Web clients explicitly opt in to a persistent 30-day cookie. Without
|
||||
// this, closing the browser ends the session even though Auth retains the
|
||||
// server-side refresh session for security/audit purposes.
|
||||
var loginData = DeserializePayload.Deserialize(payload);
|
||||
var rememberMe = loginData?.TryGetValue("rememberMe", out var rememberValue) == true
|
||||
&& rememberValue.ValueKind is System.Text.Json.JsonValueKind.True;
|
||||
var targetUrl = AuthUserTargetUrl;
|
||||
|
||||
var request = new
|
||||
{
|
||||
functionName = "loginUser",
|
||||
payload,
|
||||
reference = "LoginUser"
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(request);
|
||||
|
||||
var forwardRequest = new HttpRequestMessage(HttpMethod.Post, targetUrl)
|
||||
{
|
||||
Content = new StringContent(json, Encoding.UTF8, "application/json")
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
var response = await _httpClient.SendAsync(forwardRequest);
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var authResponse = JsonSerializer.Deserialize<AuthResponse>( responseContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||
|
||||
if (authResponse == null)
|
||||
return new AuthResponse { StatusCode = 500, Success = false, Message = "Empty response from auth service", Data = null };
|
||||
|
||||
if (authResponse.Success && authResponse.Data is JsonElement dataElement)
|
||||
{
|
||||
SetAuthCookiesFromData(httpContext, dataElement, rememberMe);
|
||||
}
|
||||
|
||||
return authResponse;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"Auth service error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Sets the access_token (and refresh_token if present) cookies from an auth-service data payload.</summary>
|
||||
private void SetAuthCookiesFromData(HttpContext httpContext, JsonElement dataElement, bool persistent = true)
|
||||
{
|
||||
string? accessToken = null;
|
||||
if (dataElement.TryGetProperty("accessToken", out var tokenProp) ||
|
||||
dataElement.TryGetProperty("AccessToken", out tokenProp))
|
||||
accessToken = tokenProp.GetString();
|
||||
if (!string.IsNullOrEmpty(accessToken))
|
||||
SetAccessTokenCookieInternal(httpContext, accessToken, persistent);
|
||||
|
||||
string? refreshToken = null;
|
||||
if (dataElement.TryGetProperty("refreshToken", out var refreshProp) ||
|
||||
dataElement.TryGetProperty("RefreshToken", out refreshProp))
|
||||
refreshToken = refreshProp.GetString();
|
||||
if (!string.IsNullOrEmpty(refreshToken))
|
||||
SetRefreshTokenCookie(httpContext, refreshToken, persistent);
|
||||
}
|
||||
|
||||
public void SetAccessTokenCookie(HttpContext httpContext, string token)
|
||||
=> SetAccessTokenCookieInternal(httpContext, token, persistent: true);
|
||||
|
||||
private void SetAccessTokenCookieInternal(HttpContext httpContext, string token, bool persistent)
|
||||
{
|
||||
var requestHost = httpContext.Request.Host.Host;
|
||||
var forwardedProto = httpContext.Request.Headers["X-Forwarded-Proto"].FirstOrDefault();
|
||||
var isHttpsRequest =
|
||||
httpContext.Request.IsHttps ||
|
||||
string.Equals(forwardedProto, "https", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
httpContext.Response.Cookies.Append("access_token", token, new CookieOptions
|
||||
{
|
||||
HttpOnly = true,
|
||||
Secure = isHttpsRequest,
|
||||
SameSite = isHttpsRequest ? SameSiteMode.None : SameSiteMode.Lax,
|
||||
Expires = persistent ? DateTimeOffset.UtcNow.AddDays(30) : null,
|
||||
Path = "/",
|
||||
Domain = IsLocalHost(requestHost) ? null : "hexafit.hexdive.com"
|
||||
});
|
||||
}
|
||||
|
||||
public void SetRefreshTokenCookie(HttpContext httpContext, string refreshToken, bool persistent = true)
|
||||
{
|
||||
var requestHost = httpContext.Request.Host.Host;
|
||||
var forwardedProto = httpContext.Request.Headers["X-Forwarded-Proto"].FirstOrDefault();
|
||||
var isHttpsRequest =
|
||||
httpContext.Request.IsHttps ||
|
||||
string.Equals(forwardedProto, "https", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
httpContext.Response.Cookies.Append("refresh_token", refreshToken, new CookieOptions
|
||||
{
|
||||
HttpOnly = true,
|
||||
Secure = isHttpsRequest,
|
||||
SameSite = isHttpsRequest ? SameSiteMode.None : SameSiteMode.Lax,
|
||||
Expires = persistent ? DateTimeOffset.UtcNow.AddDays(30) : null,
|
||||
Path = "/",
|
||||
Domain = IsLocalHost(requestHost) ? null : "hexafit.hexdive.com"
|
||||
});
|
||||
}
|
||||
|
||||
public void ClearAuthCookies(HttpContext httpContext)
|
||||
{
|
||||
var requestHost = httpContext.Request.Host.Host;
|
||||
var domain = IsLocalHost(requestHost) ? null : "hexafit.hexdive.com";
|
||||
var options = new CookieOptions { Path = "/", Domain = domain };
|
||||
httpContext.Response.Cookies.Delete("access_token", options);
|
||||
httpContext.Response.Cookies.Delete("refresh_token", options);
|
||||
}
|
||||
|
||||
public async Task<AuthResponse> RefreshToken(object payload, HttpContext httpContext)
|
||||
{
|
||||
var targetUrl = AuthUserTargetUrl;
|
||||
|
||||
// The refresh token lives in an httpOnly cookie so the browser can trigger a
|
||||
// silent refresh without ever holding it in JS. Fall back to the request payload
|
||||
// (e.g. mobile clients that pass it explicitly).
|
||||
string? refreshToken = null;
|
||||
try
|
||||
{
|
||||
var data = DeserializePayload.Deserialize(payload);
|
||||
if (data.TryGetValue("refreshToken", out var rt) && rt.ValueKind == JsonValueKind.String)
|
||||
refreshToken = rt.GetString();
|
||||
}
|
||||
catch { /* payload may be empty on cookie-driven refresh */ }
|
||||
|
||||
if (string.IsNullOrEmpty(refreshToken))
|
||||
refreshToken = httpContext.Request.Cookies["refresh_token"];
|
||||
|
||||
if (string.IsNullOrEmpty(refreshToken))
|
||||
{
|
||||
ClearAuthCookies(httpContext);
|
||||
return new AuthResponse { StatusCode = 401, Success = false, Message = "Missing refresh token", Data = null };
|
||||
}
|
||||
|
||||
var deviceName = httpContext.Request.Headers["User-Agent"].ToString();
|
||||
var request = new
|
||||
{
|
||||
functionName = "refreshToken",
|
||||
payload = new { refreshToken, deviceName },
|
||||
reference = "RefreshToken"
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(request);
|
||||
|
||||
var forwardRequest = new HttpRequestMessage(HttpMethod.Post, targetUrl)
|
||||
{
|
||||
Content = new StringContent(json, Encoding.UTF8, "application/json")
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(deviceName))
|
||||
forwardRequest.Headers.TryAddWithoutValidation("User-Agent", deviceName);
|
||||
|
||||
var forwardedFor = httpContext.Connection.RemoteIpAddress?.ToString();
|
||||
if (!string.IsNullOrWhiteSpace(forwardedFor))
|
||||
forwardRequest.Headers.TryAddWithoutValidation("X-Forwarded-For", forwardedFor);
|
||||
|
||||
try
|
||||
{
|
||||
var response = await _httpClient.SendAsync(forwardRequest);
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var authResponse = JsonSerializer.Deserialize<AuthResponse>(responseContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||
|
||||
if (authResponse == null)
|
||||
return new AuthResponse { StatusCode = 500, Success = false, Message = "Empty response from auth service", Data = null };
|
||||
|
||||
if (authResponse.Success && authResponse.Data is JsonElement dataElement)
|
||||
{
|
||||
// Core-Hex-Auth rotates the refresh token; persist both new cookies.
|
||||
SetAuthCookiesFromData(httpContext, dataElement);
|
||||
return authResponse;
|
||||
}
|
||||
|
||||
// Refresh token invalid/expired — clear cookies and report 401 so the
|
||||
// frontend redirects to login rather than surfacing a 500.
|
||||
ClearAuthCookies(httpContext);
|
||||
return new AuthResponse { StatusCode = 401, Success = false, Message = "Session expired. Please log in again.", Data = null };
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new AuthResponse { StatusCode = 500, Success = false, Message = $"Error communicating with auth service: {ex.Message}", Data = null };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//customer ta only use? why
|
||||
public async Task<AuthResponse> VerifyOTPForCus(object payload, HttpContext httpContext)
|
||||
{
|
||||
|
||||
var data = DeserializePayload.Deserialize(payload);
|
||||
|
||||
|
||||
|
||||
var targetUrl = AuthRecoveryTargetUrl;
|
||||
var request = new
|
||||
{
|
||||
functionName = "verifyOTP",
|
||||
payload,
|
||||
reference = "verify-otp"
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(request);
|
||||
|
||||
var forwardRequest = new HttpRequestMessage(HttpMethod.Post, targetUrl)
|
||||
{
|
||||
Content = new StringContent(json, Encoding.UTF8, "application/json")
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
var response = await _httpClient.SendAsync(forwardRequest);
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
var authResponse = JsonSerializer.Deserialize<AuthResponse>(responseContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||
|
||||
if (authResponse == null)
|
||||
throw new Exception("Empty response from auth service");
|
||||
|
||||
string identifireType = DataExtractor.GetRequiredString(data, "identifireType");
|
||||
var identifier = DataExtractor.GetRequiredString(data, "identifier");
|
||||
|
||||
Guid userId = DataExtractor.GetUserIdFromContext(httpContext);
|
||||
|
||||
await _UoW.BeginAsync();
|
||||
try
|
||||
{
|
||||
bool result = await _cusRepo.VerifyCustomer(userId, identifireType, identifier);
|
||||
if (!result)
|
||||
throw new Exception("verfifying faled");
|
||||
await _UoW.CommitAsync();
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
await _UoW.RollbackAsync();
|
||||
throw new Exception($"{ex.Message}");
|
||||
}
|
||||
|
||||
return authResponse;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new AuthResponse { StatusCode = 500, Success = false, Message = $"Error communicating with auth service: {ex.Message}", Data = null };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async Task<AuthResponse> VerifyOtpForLogin(object payload, HttpContext httpContext)
|
||||
{
|
||||
var targetUrl = AuthUserTargetUrl;
|
||||
var request = new
|
||||
{
|
||||
functionName = "VerifyOtpForLogin",
|
||||
payload,
|
||||
reference = "verify-otp-for-login"
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(request);
|
||||
|
||||
var forwardRequest = new HttpRequestMessage(HttpMethod.Post, targetUrl)
|
||||
{
|
||||
Content = new StringContent(json, Encoding.UTF8, "application/json")
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
var response = await _httpClient.SendAsync(forwardRequest);
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
var authResponse = JsonSerializer.Deserialize<AuthResponse>(responseContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||
|
||||
return authResponse ?? new AuthResponse { StatusCode = 500, Success = false, Message = "Empty response from auth service", Data = null };
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new AuthResponse { StatusCode = 500, Success = false, Message = $"Error communicating with auth service: {ex.Message}", Data = null };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public async Task<AuthResponse> IsAvailable(object payload, HttpContext httpContext)
|
||||
{
|
||||
var targetUrl = AuthAltTargetUrl;
|
||||
var request = new
|
||||
{
|
||||
functionName = "IsAvailable",
|
||||
payload,
|
||||
reference = "is-available"
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(request);
|
||||
|
||||
var forwardRequest = new HttpRequestMessage(HttpMethod.Post, targetUrl)
|
||||
{
|
||||
Content = new StringContent(json, Encoding.UTF8, "application/json")
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
var response = await _httpClient.SendAsync(forwardRequest);
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
var authResponse = JsonSerializer.Deserialize<AuthResponse>(responseContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||
|
||||
return authResponse ?? new AuthResponse { StatusCode = 500, Success = false, Message = "Empty response from auth service", Data = null };
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new AuthResponse { StatusCode = 500, Success = false, Message = $"Error communicating with auth service: {ex.Message}", Data = null };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async Task<AuthResponse> RegisterUser(object payload, HttpContext httpContext)
|
||||
{
|
||||
var targetUrl = AuthUserTargetUrl;
|
||||
var request = new
|
||||
{
|
||||
functionName = "registerUser",
|
||||
payload,
|
||||
reference = "register-user"
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(request);
|
||||
|
||||
var forwardRequest = new HttpRequestMessage(HttpMethod.Post, targetUrl)
|
||||
{
|
||||
Content = new StringContent(json, Encoding.UTF8, "application/json")
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
var response = await _httpClient.SendAsync(forwardRequest);
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
var authResponse = JsonSerializer.Deserialize<AuthResponse>(responseContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||
|
||||
return authResponse ?? new AuthResponse { StatusCode = 500, Success = false, Message = "Empty response from auth service", Data = null };
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new AuthResponse { StatusCode = 500, Success = false, Message = $"Error communicating with auth service: {ex.Message}", Data = null };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async Task<AuthResponse> GetUserDetails(object payload, HttpContext httpContext)
|
||||
{
|
||||
var targetUrl = AuthUserTargetUrl;
|
||||
var request = new
|
||||
{
|
||||
functionName = "getUserDetails",
|
||||
payload,
|
||||
reference = "user-details"
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(request);
|
||||
|
||||
var forwardRequest = new HttpRequestMessage(HttpMethod.Post, targetUrl)
|
||||
{
|
||||
Content = new StringContent(json, Encoding.UTF8, "application/json")
|
||||
};
|
||||
|
||||
var authHeader = httpContext.Request.Headers["Authorization"].FirstOrDefault();
|
||||
if (!string.IsNullOrEmpty(authHeader))
|
||||
{
|
||||
forwardRequest.Headers.Authorization =
|
||||
new System.Net.Http.Headers.AuthenticationHeaderValue(
|
||||
"Bearer",
|
||||
authHeader.Replace("Bearer ", "")
|
||||
);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var response = await _httpClient.SendAsync(forwardRequest);
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
var authResponse = JsonSerializer.Deserialize<AuthResponse>(responseContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||
|
||||
return authResponse ?? new AuthResponse { StatusCode = 500, Success = false, Message = "Empty response from auth service", Data = null };
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new AuthResponse { StatusCode = 500, Success = false, Message = $"Error communicating with auth service: {ex.Message}", Data = null };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async Task<AuthResponse> UpdateUser(object payload, HttpContext httpContext)
|
||||
{
|
||||
var targetUrl = AuthUserTargetUrl;
|
||||
var request = new
|
||||
{
|
||||
functionName = "UpdateUser",
|
||||
payload,
|
||||
reference = "user-details"
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(request);
|
||||
|
||||
var forwardRequest = new HttpRequestMessage(HttpMethod.Post, targetUrl)
|
||||
{
|
||||
Content = new StringContent(json, Encoding.UTF8, "application/json")
|
||||
};
|
||||
|
||||
// Web clients authenticate via the access_token cookie, not an Authorization
|
||||
// header — forward whichever is present so the auth service can read the userId.
|
||||
ApplyAuthHeader(forwardRequest, httpContext);
|
||||
|
||||
try
|
||||
{
|
||||
var response = await _httpClient.SendAsync(forwardRequest);
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
var authResponse = JsonSerializer.Deserialize<AuthResponse>(responseContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||
|
||||
return authResponse ?? new AuthResponse { StatusCode = 500, Success = false, Message = "Empty response from auth service", Data = null };
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new AuthResponse { StatusCode = 500, Success = false, Message = $"Error communicating with auth service: {ex.Message}", Data = null };
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<AuthResponse> AdminUpdateUser(object payload, HttpContext httpContext)
|
||||
{
|
||||
var targetUrl = AuthUserTargetUrl;
|
||||
var request = new
|
||||
{
|
||||
functionName = "adminUpdateUser",
|
||||
payload,
|
||||
reference = "admin-update-user"
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(request);
|
||||
|
||||
var forwardRequest = new HttpRequestMessage(HttpMethod.Post, targetUrl)
|
||||
{
|
||||
Content = new StringContent(json, Encoding.UTF8, "application/json")
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
var response = await _httpClient.SendAsync(forwardRequest);
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
var authResponse = JsonSerializer.Deserialize<AuthResponse>(responseContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||
|
||||
return authResponse ?? new AuthResponse { StatusCode = 500, Success = false, Message = "Empty response from auth service", Data = null };
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new AuthResponse { StatusCode = 500, Success = false, Message = $"Error communicating with auth service: {ex.Message}", Data = null };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Forwards a recovery-manager function (forgotPassword / resetPassword) — no auth required.</summary>
|
||||
private async Task<AuthResponse> ForwardToRecovery(string functionName, object payload)
|
||||
{
|
||||
var request = new { functionName, payload, reference = functionName };
|
||||
var json = JsonSerializer.Serialize(request);
|
||||
var forwardRequest = new HttpRequestMessage(HttpMethod.Post, AuthRecoveryTargetUrl)
|
||||
{
|
||||
Content = new StringContent(json, Encoding.UTF8, "application/json")
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
var response = await _httpClient.SendAsync(forwardRequest);
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var authResponse = JsonSerializer.Deserialize<AuthResponse>(responseContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||
return authResponse ?? new AuthResponse { StatusCode = 500, Success = false, Message = "Empty response from auth service", Data = null };
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new AuthResponse { StatusCode = 500, Success = false, Message = $"Error communicating with auth service: {ex.Message}", Data = null };
|
||||
}
|
||||
}
|
||||
|
||||
public Task<AuthResponse> ForgotPassword(object payload, HttpContext httpContext)
|
||||
=> ForwardToRecovery("forgotPassword", payload);
|
||||
|
||||
public Task<AuthResponse> ResetPassword(object payload, HttpContext httpContext)
|
||||
=> ForwardToRecovery("resetPassword", payload);
|
||||
|
||||
public Task<AuthResponse> ResetPasswordWithToken(object payload, HttpContext httpContext)
|
||||
=> ForwardToRecovery("resetPasswordWithToken", payload);
|
||||
|
||||
// Confirms the caller's own password (used to unlock sensitive views). Returns { valid }.
|
||||
public async Task<AuthResponse> VerifyPassword(object payload, HttpContext httpContext)
|
||||
{
|
||||
var request = new { functionName = "VerifyPassword", payload, reference = "verify-password" };
|
||||
var json = JsonSerializer.Serialize(request);
|
||||
var forwardRequest = new HttpRequestMessage(HttpMethod.Post, AuthUserTargetUrl)
|
||||
{
|
||||
Content = new StringContent(json, Encoding.UTF8, "application/json")
|
||||
};
|
||||
ApplyAuthHeader(forwardRequest, httpContext);
|
||||
|
||||
try
|
||||
{
|
||||
var response = await _httpClient.SendAsync(forwardRequest);
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var authResponse = JsonSerializer.Deserialize<AuthResponse>(responseContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||
return authResponse ?? new AuthResponse { StatusCode = 500, Success = false, Message = "Empty response from auth service", Data = null };
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new AuthResponse { StatusCode = 500, Success = false, Message = $"Error communicating with auth service: {ex.Message}", Data = null };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Sets the outgoing Bearer token from the Authorization header, the MobileAuthToken header, or the access_token cookie.</summary>
|
||||
private static void ApplyAuthHeader(HttpRequestMessage req, HttpContext ctx)
|
||||
{
|
||||
string? token = null;
|
||||
|
||||
var authHeader = ctx.Request.Headers["Authorization"].FirstOrDefault();
|
||||
if (!string.IsNullOrWhiteSpace(authHeader))
|
||||
token = authHeader.Replace("Bearer ", "").Trim();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(token))
|
||||
{
|
||||
var mobile = ctx.Request.Headers["MobileAuthToken"].FirstOrDefault();
|
||||
if (!string.IsNullOrWhiteSpace(mobile) && mobile.StartsWith("Bearer "))
|
||||
token = mobile.Substring("Bearer ".Length).Trim();
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(token))
|
||||
token = ctx.Request.Cookies["access_token"];
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(token))
|
||||
req.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// new otp verfy for client
|
||||
public async Task<AuthResponse> VerifyOTP(object payload, HttpContext httpContext)
|
||||
{
|
||||
|
||||
var data = DeserializePayload.Deserialize(payload);
|
||||
|
||||
|
||||
|
||||
var targetUrl = AuthRecoveryTargetUrl;
|
||||
var request = new
|
||||
{
|
||||
functionName = "verifyOTP",
|
||||
payload,
|
||||
reference = "verify-otp"
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(request);
|
||||
|
||||
var forwardRequest = new HttpRequestMessage(HttpMethod.Post, targetUrl)
|
||||
{
|
||||
Content = new StringContent(json, Encoding.UTF8, "application/json")
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
var response = await _httpClient.SendAsync(forwardRequest);
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
var authResponse = JsonSerializer.Deserialize<AuthResponse>(responseContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||
|
||||
if (authResponse == null)
|
||||
throw new Exception("Empty response from auth service");
|
||||
|
||||
return authResponse;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new AuthResponse { StatusCode = 500, Success = false, Message = $"Error communicating with auth service: {ex.Message}", Data = null };
|
||||
}
|
||||
}
|
||||
|
||||
//Logout user by clearing cookie
|
||||
public async Task<AuthResponse> LogOut(object payload, HttpContext httpContext)
|
||||
{
|
||||
var targetUrl = AuthUserTargetUrl;
|
||||
var request = new
|
||||
{
|
||||
functionName = "LogoutUser",
|
||||
payload,
|
||||
reference = "log-out"
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(request);
|
||||
|
||||
var forwardRequest = new HttpRequestMessage(HttpMethod.Post, targetUrl)
|
||||
{
|
||||
Content = new StringContent(json, Encoding.UTF8, "application/json")
|
||||
};
|
||||
|
||||
// Always clear cookies locally, even if the remote revoke fails — the user
|
||||
// clicked logout and their browser session must end.
|
||||
ClearAuthCookies(httpContext);
|
||||
|
||||
try
|
||||
{
|
||||
var response = await _httpClient.SendAsync(forwardRequest);
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
var authResponse = JsonSerializer.Deserialize<AuthResponse>(responseContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||
|
||||
return authResponse ?? new AuthResponse { StatusCode = 200, Success = true, Message = "Logged out", Data = null };
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new AuthResponse { StatusCode = 200, Success = true, Message = "Logged out", Data = null };
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsLocalHost(string? host)
|
||||
{
|
||||
return string.Equals(host, "localhost", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(host, "127.0.0.1", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user