littleshop/LittleShop.Client/Services/AuthenticationService.cs
sysadmin 1f7c0af497 Add LittleShop.Client SDK library with complete API wrapper
Features:
- Complete .NET client SDK for LittleShop API
- JWT authentication with automatic token management
- Catalog service for products and categories
- Order service with payment creation
- Retry policies using Polly for resilience
- Error handling middleware
- Dependency injection support
- Comprehensive documentation and examples

SDK Components:
- Authentication service with token refresh
- Strongly-typed models for all API responses
- HTTP handlers for retry and error handling
- Extension methods for easy DI registration
- Example console application demonstrating usage

Test Updates:
- Fixed test compilation errors
- Updated test data builders for new models
- Corrected service constructor dependencies
- Fixed enum value changes (PaymentStatus, OrderStatus)

Documentation:
- Complete project README with features and usage
- Client SDK README with detailed examples
- API endpoint documentation
- Security considerations
- Deployment guidelines

Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-20 18:15:35 +01:00

126 lines
4.1 KiB
C#

using System.IdentityModel.Tokens.Jwt;
using System.Net.Http.Json;
using LittleShop.Client.Models;
using Microsoft.Extensions.Logging;
namespace LittleShop.Client.Services;
public class AuthenticationService : IAuthenticationService
{
private readonly HttpClient _httpClient;
private readonly ILogger<AuthenticationService> _logger;
private string? _currentToken;
private DateTime? _tokenExpiry;
public AuthenticationService(HttpClient httpClient, ILogger<AuthenticationService> logger)
{
_httpClient = httpClient;
_logger = logger;
}
public async Task<ApiResponse<LoginResponse>> LoginAsync(string username, string password)
{
try
{
var request = new LoginRequest { Username = username, Password = password };
var response = await _httpClient.PostAsJsonAsync("api/auth/login", request);
if (response.IsSuccessStatusCode)
{
var loginResponse = await response.Content.ReadFromJsonAsync<LoginResponse>();
if (loginResponse != null)
{
SetToken(loginResponse.Token);
return ApiResponse<LoginResponse>.Success(loginResponse);
}
}
var error = await response.Content.ReadAsStringAsync();
return ApiResponse<LoginResponse>.Failure(
error ?? "Login failed",
response.StatusCode);
}
catch (Exception ex)
{
_logger.LogError(ex, "Login failed");
return ApiResponse<LoginResponse>.Failure(
ex.Message,
System.Net.HttpStatusCode.InternalServerError);
}
}
public async Task<ApiResponse<LoginResponse>> RefreshTokenAsync()
{
if (string.IsNullOrEmpty(_currentToken))
{
return ApiResponse<LoginResponse>.Failure(
"No token to refresh",
System.Net.HttpStatusCode.Unauthorized);
}
try
{
_httpClient.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", _currentToken);
var response = await _httpClient.PostAsync("api/auth/refresh", null);
if (response.IsSuccessStatusCode)
{
var loginResponse = await response.Content.ReadFromJsonAsync<LoginResponse>();
if (loginResponse != null)
{
SetToken(loginResponse.Token);
return ApiResponse<LoginResponse>.Success(loginResponse);
}
}
return ApiResponse<LoginResponse>.Failure(
"Token refresh failed",
response.StatusCode);
}
catch (Exception ex)
{
_logger.LogError(ex, "Token refresh failed");
return ApiResponse<LoginResponse>.Failure(
ex.Message,
System.Net.HttpStatusCode.InternalServerError);
}
}
public void SetToken(string token)
{
_currentToken = token;
_httpClient.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
// Parse token to get expiry
try
{
var handler = new JwtSecurityTokenHandler();
var jsonToken = handler.ReadJwtToken(token);
_tokenExpiry = jsonToken.ValidTo;
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to parse token expiry");
_tokenExpiry = DateTime.UtcNow.AddHours(1); // Default to 1 hour
}
}
public string? GetToken() => _currentToken;
public bool IsAuthenticated()
{
return !string.IsNullOrEmpty(_currentToken) &&
_tokenExpiry.HasValue &&
_tokenExpiry.Value > DateTime.UtcNow;
}
public void Logout()
{
_currentToken = null;
_tokenExpiry = null;
_httpClient.DefaultRequestHeaders.Authorization = null;
}
}