S3Lab.Box.Auth
1.1.0
See the version list below for details.
dotnet add package S3Lab.Box.Auth --version 1.1.0
NuGet\Install-Package S3Lab.Box.Auth -Version 1.1.0
<PackageReference Include="S3Lab.Box.Auth" Version="1.1.0" />
<PackageVersion Include="S3Lab.Box.Auth" Version="1.1.0" />
<PackageReference Include="S3Lab.Box.Auth" />
paket add S3Lab.Box.Auth --version 1.1.0
#r "nuget: S3Lab.Box.Auth, 1.1.0"
#:package S3Lab.Box.Auth@1.1.0
#addin nuget:?package=S3Lab.Box.Auth&version=1.1.0
#tool nuget:?package=S3Lab.Box.Auth&version=1.1.0
S3Lab.Box
Решение для ASP.NET Core приложений, включающее библиотеки для аутентификации и работы с данными.
Проекты в решении
S3Lab.Box.Auth
Библиотека для аутентификации ASP.NET Core приложений с использованием API ключей.
Описание
S3Lab.Box.Auth предоставляет простое и эффективное решение для защиты API endpoints с помощью API ключей. Библиотека включает в себя middleware для проверки заголовка X-API-Key
и расширения для удобной интеграции в ASP.NET Core приложения.
Возможности
- 🔐 Аутентификация по API ключу через заголовок
X-API-Key
- 🚫 Автоматическое отклонение запросов без валидного ключа
- 🔓 Исключения для определенных маршрутов (Scalar, OpenAPI)
- ⚡ Поддержка preflight запросов (OPTIONS)
- 🛠️ Простая интеграция через extension методы
Установка
dotnet add package S3Lab.Box.Auth
Быстрый старт
- Настройка конфигурации
Добавьте API ключ в ваш appsettings.json
:
{
"ApiKey": "your-secret-api-key-here"
}
- Регистрация сервисов
В Program.cs
или Startup.cs
:
using S3Lab.Box.Auth.Extensions;
var builder = WebApplication.CreateBuilder(args);
// Добавление сервисов
builder.Services.AddApplicationReferences(builder.Configuration);
var app = builder.Build();
// Регистрация middleware
app.UseApiKeyMiddleware();
app.Run();
- Использование
После настройки все запросы к вашему API должны включать заголовок X-API-Key
с валидным ключом:
curl -H "X-API-Key: your-secret-api-key-here" https://your-api.com/endpoint
Исключения
Middleware автоматически пропускает следующие типы запросов:
- OPTIONS запросы (preflight для CORS)
- Scalar endpoints (
/scalar/*
) - OpenAPI endpoints (
/openApi/*
)
Конфигурация
API ключ должен быть указан в конфигурации приложения:
{
"ApiKey": "your-secret-api-key-here"
}
Для production окружения рекомендуется использовать переменные окружения:
export ApiKey="your-production-api-key"
Обработка ошибок
При отсутствии или неверном API ключе middleware возвращает:
- HTTP Status Code: 401 Unauthorized
- Response Body: "Unauthorized: Invalid or missing X-API-Key"
Безопасность
- API ключ должен быть достаточно длинным и случайным
- Используйте HTTPS в production окружении
- Не храните API ключи в исходном коде
- Регулярно ротируйте API ключи
S3Lab.Box.Data
Библиотека для работы с данными в ASP.NET Core приложениях, предоставляющая базовые сущности, интерфейсы и репозиторий для Entity Framework Core.
Описание
S3Lab.Box.Data предоставляет набор базовых классов и интерфейсов для упрощения работы с данными в .NET приложениях. Библиотека включает в себя готовые сущности с аудитом и архивированием, универсальный репозиторий и расширения для Entity Framework Core.
Возможности
- 🏗️ Базовые сущности с поддержкой различных типов ключей
- 📝 Аудит сущностей (создание, изменение, пользователи)
- 🗄️ Архивирование сущностей (мягкое удаление)
- 📚 Универсальный репозиторий с полным набором CRUD операций
- 🔍 Поддержка Include для связанных сущностей
- ⚡ Асинхронные операции с поддержкой CancellationToken
- 🛠️ Расширения для Entity Framework Core
Установка
dotnet add package S3Lab.Box.Data
Требования
- .NET 9.0 или выше
- Entity Framework Core
Структура библиотеки
Сущности (Entities)
Entity<TKey>
Базовая сущность с идентификатором:
public abstract class Entity<TKey> : IEntity<TKey>, IEntity
{
public required TKey Id { get; set; }
}
AuditableEntity<TKey, TUserKey>
Сущность с аудитом (отслеживание создания и изменения):
public abstract class AuditableEntity<TKey, TUserKey> : Entity<TKey>, IAuditableEntity<TUserKey>
{
public TUserKey CreatedBy { get; set; }
public TUserKey UpdatedBy { get; set; }
public DateTime Created { get; set; }
public DateTime? Updated { get; set; }
}
ArchivableEntity<TKey, TUserKey>
Архивируемая сущность с мягким удалением:
public class ArchivableEntity<TKey, TUserKey> : AuditableEntity<TKey, TUserKey>, IArchivableEntity
{
public bool IsDeleted { get; set; }
}
DictionaryEntity<TKey>
Справочная сущность с именем:
public abstract class DictionaryEntity<TKey> : IDictionaryEntity<TKey>
{
public TKey Id { get; set; }
public required string Name { get; set; }
}
Интерфейсы (Interfaces)
IEntity<TKey>
Базовый интерфейс для сущностей с идентификатором:
public interface IEntity<TKey>
{
TKey Id { get; set; }
}
IAuditableEntity<TUserKey>
Интерфейс для аудируемых сущностей:
public interface IAuditableEntity<TUserKey>
{
TUserKey CreatedBy { get; set; }
TUserKey UpdatedBy { get; set; }
DateTime Created { get; set; }
DateTime? Updated { get; set; }
}
IArchivableEntity
Интерфейс для архивируемых сущностей:
public interface IArchivableEntity
{
bool IsDeleted { get; set; }
}
IRepository<TEntity, TKey>
Универсальный интерфейс репозитория с полным набором CRUD операций:
public interface IRepository<TEntity, TKey>
{
// Получение по ID
Task<TEntity?> GetByIdAsync(TKey id);
Task<TEntity?> GetByIdAsync(TKey id, IEnumerable<string> includePaths);
Task<TEntity?> GetByIdAsync(TKey id, bool asNoTracking);
// Получение списка по ID
Task<List<TEntity>> GetByIdListAsync(IEnumerable<TKey> idList);
// Добавление
Task<TEntity> AddAsync(TEntity entity);
Task AddRangeAsync(IEnumerable<TEntity> entities);
// Обновление
Task UpdateAsync(TEntity entity);
// Удаление
Task DeleteAsync(TEntity entity);
Task DeleteRangeAsync(IEnumerable<TEntity> entities);
// Сохранение
Task SaveAsync();
// Проверка существования
Task<bool> IsExistAsync(TKey id);
}
Репозиторий (Repository)
Repository<TEntity, TKey>
Универсальная реализация репозитория с поддержкой:
- Асинхронных операций
- CancellationToken
- Include для связанных сущностей
- AsNoTracking для оптимизации производительности
- Пакетных операций
UnitOfWork
Реализация паттерна Unit of Work для управления транзакциями:
public interface IUnitOfWork : IDisposable
{
IRepository<TEntity, TKey> Repository<TEntity, TKey>();
Task<int> SaveChangesAsync();
Task<IDbContextTransaction> BeginTransactionAsync();
Task<T> ExecuteInTransactionAsync<T>(Func<Task<T>> operation);
}
Возможности UnitOfWork:
- 🏗️ Централизованное управление репозиториями
- 💾 Автоматическое управление транзакциями
- 🔄 Поддержка отката изменений при ошибках
- ⚡ Кэширование репозиториев для оптимизации
- 🛡️ Безопасное освобождение ресурсов
Расширения (Extensions)
QueryableExtensions
Расширения для работы с IQueryable:
public static IQueryable<TEntity> AddIncludes<TEntity, TKey>(
this IQueryable<TEntity> entities,
IEnumerable<string>? includePaths)
ServiceCollectionExtensions
Расширения для регистрации сервисов в DI:
// Регистрация UnitOfWork
services.AddS3LabBoxData();
// Регистрация конкретного репозитория
services.AddRepository<User, int, UserRepository>();
// Регистрация базового репозитория
services.AddRepository<Product, int>();
Быстрый старт
1. Создание сущности
public class User : AuditableEntity<int, int>
{
public string Name { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
}
public class Category : DictionaryEntity<int>
{
public Category(int id, string name) : base(id, name)
{
}
}
2. Создание репозитория
public class UserRepository : Repository<User, int>
{
public UserRepository(DbContext context) : base(context)
{
}
// Дополнительные методы специфичные для User
public async Task<User?> GetByEmailAsync(string email)
{
return await DbSet.FirstOrDefaultAsync(u => u.Email == email);
}
}
3. Регистрация в DI
// Program.cs
builder.Services.AddScoped<UserRepository>();
builder.Services.AddScoped<IRepository<User, int>, UserRepository>();
4. Использование
public class UserService
{
private readonly IRepository<User, int> _userRepository;
public UserService(IRepository<User, int> userRepository)
{
_userRepository = userRepository;
}
public async Task<User> CreateUserAsync(User user)
{
user.Created = DateTime.UtcNow;
user.CreatedBy = 1; // ID текущего пользователя
return await _userRepository.AddAsync(user);
}
public async Task<User?> GetUserWithDetailsAsync(int id)
{
return await _userRepository.GetByIdAsync(id, new[] { "Orders", "Profile" });
}
public async Task<List<User>> GetUsersByIdsAsync(IEnumerable<int> ids)
{
return await _userRepository.GetByIdListAsync(ids);
}
}
5. Использование UnitOfWork
public class OrderService
{
private readonly IUnitOfWork _unitOfWork;
public OrderService(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public async Task<Order> CreateOrderWithItemsAsync(Order order, List<OrderItem> items)
{
// Использование транзакции для атомарной операции
return await _unitOfWork.ExecuteInTransactionAsync(async () =>
{
var orderRepo = _unitOfWork.Repository<Order, int>();
var itemRepo = _unitOfWork.Repository<OrderItem, int>();
// Создаем заказ
var createdOrder = await orderRepo.AddAsync(order);
// Добавляем товары к заказу
foreach (var item in items)
{
item.OrderId = createdOrder.Id;
await itemRepo.AddAsync(item);
}
// Сохраняем все изменения
await _unitOfWork.SaveChangesAsync();
return createdOrder;
});
}
public async Task<bool> TransferBetweenOrdersAsync(int fromOrderId, int toOrderId, int itemId)
{
try
{
using var transaction = await _unitOfWork.BeginTransactionAsync();
var itemRepo = _unitOfWork.Repository<OrderItem, int>();
// Получаем товар
var item = await itemRepo.GetByIdAsync(itemId);
if (item == null) return false;
// Обновляем заказ
item.OrderId = toOrderId;
await itemRepo.UpdateAsync(item);
// Сохраняем изменения
await _unitOfWork.SaveChangesAsync();
// Подтверждаем транзакцию
await transaction.CommitAsync();
return true;
}
catch
{
// Транзакция автоматически откатится при исключении
return false;
}
}
}
Примеры использования
Работа с аудируемыми сущностями
public class Product : AuditableEntity<int, int>
{
public string Name { get; set; } = string.Empty;
public decimal Price { get; set; }
}
// Создание
var product = new Product
{
Name = "Sample Product",
Price = 99.99m,
Created = DateTime.UtcNow,
CreatedBy = currentUserId
};
await _repository.AddAsync(product);
// Обновление
product.Price = 89.99m;
product.Updated = DateTime.UtcNow;
product.UpdatedBy = currentUserId;
await _repository.UpdateAsync(product);
Работа с архивируемыми сущностями
public class Order : ArchivableEntity<int, int>
{
public string OrderNumber { get; set; } = string.Empty;
public decimal Total { get; set; }
}
// Мягкое удаление
var order = await _repository.GetByIdAsync(orderId);
if (order != null)
{
order.IsDeleted = true;
order.Updated = DateTime.UtcNow;
order.UpdatedBy = currentUserId;
await _repository.UpdateAsync(order);
}
Использование Include
// Получение пользователя с заказами и профилем
var user = await _userRepository.GetByIdAsync(
userId,
new[] { "Orders", "Profile", "Orders.Items" }
);
// Получение без отслеживания изменений
var user = await _userRepository.GetByIdAsync(
userId,
new[] { "Orders" },
asNoTracking: true
);
Пакетные операции
// Добавление нескольких сущностей
var users = new List<User>
{
new User { Name = "User1", Email = "user1@example.com" },
new User { Name = "User2", Email = "user2@example.com" }
};
await _userRepository.AddRangeAsync(users);
await _userRepository.SaveAsync();
// Удаление нескольких сущностей
var usersToDelete = await _userRepository.GetByIdListAsync(userIds);
await _userRepository.DeleteRangeAsync(usersToDelete);
await _userRepository.SaveAsync();
Конфигурация Entity Framework
DbContext
public class ApplicationDbContext : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Category> Categories { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Конфигурация для аудируемых сущностей
modelBuilder.Entity<User>()
.Property(u => u.Created)
.HasDefaultValueSql("GETUTCDATE()");
// Конфигурация для архивируемых сущностей
modelBuilder.Entity<Order>()
.HasQueryFilter(o => !o.IsDeleted);
}
}
Производительность
Рекомендации
Используйте AsNoTracking для операций только чтения:
var users = await _repository.GetByIdAsync(id, asNoTracking: true);
Применяйте Include только когда необходимо:
// Только при необходимости связанных данных var user = await _repository.GetByIdAsync(id, new[] { "Orders" });
Используйте пакетные операции для множественных изменений:
await _repository.AddRangeAsync(entities); await _repository.SaveAsync(); // Одно сохранение для всех
Применяйте CancellationToken для длительных операций:
var users = await _repository.GetByIdListAsync(ids, cancellationToken);
Лицензия
MIT License
Автор
Sazonov Andrei
Версия
1.0.0
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net9.0
- Microsoft.Extensions.Configuration (>= 9.0.0)
- Microsoft.Extensions.DependencyInjection (>= 9.0.0)
- Scalar.AspNetCore (>= 2.4.22)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.