S3Lab.Box.Auth 1.1.0

There is a newer version of this package available.
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
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="S3Lab.Box.Auth" Version="1.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="S3Lab.Box.Auth" Version="1.1.0" />
                    
Directory.Packages.props
<PackageReference Include="S3Lab.Box.Auth" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add S3Lab.Box.Auth --version 1.1.0
                    
#r "nuget: S3Lab.Box.Auth, 1.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package S3Lab.Box.Auth@1.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=S3Lab.Box.Auth&version=1.1.0
                    
Install as a Cake Addin
#tool nuget:?package=S3Lab.Box.Auth&version=1.1.0
                    
Install as a Cake Tool

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
Быстрый старт
  1. Настройка конфигурации

Добавьте API ключ в ваш appsettings.json:

{
  "ApiKey": "your-secret-api-key-here"
}
  1. Регистрация сервисов

В 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();
  1. Использование

После настройки все запросы к вашему 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);
    }
}

Производительность

Рекомендации

  1. Используйте AsNoTracking для операций только чтения:

    var users = await _repository.GetByIdAsync(id, asNoTracking: true);
    
  2. Применяйте Include только когда необходимо:

    // Только при необходимости связанных данных
    var user = await _repository.GetByIdAsync(id, new[] { "Orders" });
    
  3. Используйте пакетные операции для множественных изменений:

    await _repository.AddRangeAsync(entities);
    await _repository.SaveAsync(); // Одно сохранение для всех
    
  4. Применяйте CancellationToken для длительных операций:

    var users = await _repository.GetByIdListAsync(ids, cancellationToken);
    

Лицензия

MIT License

Автор

Sazonov Andrei

Версия

1.0.0

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.0 70 6/27/2025
1.1.0 70 6/27/2025