CG.Infrastructure.Authentication
3.10.2
dotnet add package CG.Infrastructure.Authentication --version 3.10.2
NuGet\Install-Package CG.Infrastructure.Authentication -Version 3.10.2
<PackageReference Include="CG.Infrastructure.Authentication" Version="3.10.2" />
<PackageVersion Include="CG.Infrastructure.Authentication" Version="3.10.2" />
<PackageReference Include="CG.Infrastructure.Authentication" />
paket add CG.Infrastructure.Authentication --version 3.10.2
#r "nuget: CG.Infrastructure.Authentication, 3.10.2"
#:package CG.Infrastructure.Authentication@3.10.2
#addin nuget:?package=CG.Infrastructure.Authentication&version=3.10.2
#tool nuget:?package=CG.Infrastructure.Authentication&version=3.10.2
Infrastructure.Authentication
A .NET 9.0 library that provides comprehensive ASP.NET Core Identity infrastructure with custom repository pattern implementation, designed for enterprise applications requiring flexible authentication and authorization systems.
๐ Overview
Infrastructure.Authentication is a modern, flexible authentication library that extends ASP.NET Core Identity with custom data access patterns. It provides a clean separation between business logic and data persistence, supporting both traditional Entity Framework and custom repository implementations.
๐ Current Status
โ
Production Ready: All 242 tests passing with comprehensive coverage
โ
Code Quality: Zero warnings, clean build, comprehensive null safety
โ
Modern Patterns: Latest .NET 9.0 features with best practices
โ
Enterprise Grade: Robust error handling and transaction management
โ
Well Tested: Extensive unit test coverage with clean mocking patterns
โจ Features
- ASP.NET Core Identity Integration: Full compatibility with Microsoft's Identity framework
- Custom Repository Pattern: Flexible data access layer supporting multiple data sources
- Query Constants Pattern: SQL queries defined as C# constants for better maintainability
- Transaction Support: Comprehensive transaction management for complex operations
- Null Safety: Built-in null reference handling and validation
- Clean Architecture: Separation of concerns with clear dependency boundaries
- Extensible Design: Easy to extend and customize for specific business requirements
๐๏ธ Architecture
Core Components
Infrastructure.Authentication/
โโโ Data/
โ โโโ Entities/ # Identity entities (ApplicationUser, ApplicationRole, etc.)
โ โ โโโ ApplicationUser.cs # Main user entity
โ โ โโโ ApplicationRole.cs # Main role entity
โ โ โโโ UserClaim.cs # User claim entity
โ โ โโโ RoleClaim.cs # Role claim entity
โ โ โโโ UserLogin.cs # External login entity
โ โ โโโ UserRole.cs # User-role relationship entity
โ โ โโโ UserToken.cs # User token entity
โ โ โโโ TestUsers.cs # Test data for development
โ โ โโโ UserJson.cs # JSON user data entity
โ โโโ Repositories/ # Data access layer
โ โ โโโ UserRepository.cs # User data operations (includes claims, logins, roles, tokens)
โ โ โโโ RoleRepository.cs # Role data operations (includes role claims)
โโโ Providers/ # Business logic providers
โ โโโ UserProvider.cs # User management operations
โ โโโ RoleProvider.cs # Role management operations
โ โโโ UserClaimProvider.cs # User claim operations
โ โโโ RoleClaimProvider.cs # Role claim operations
โ โโโ UserLoginProvider.cs # External login operations
โ โโโ UserRoleProvider.cs # User-role relationship operations
โ โโโ UserTokenProvider.cs # User token operations
โโโ Services/ # Application services
โ โโโ AuthenticationDatabaseService.cs # Database seeding and setup
โโโ Options/ # Configuration options
โ โโโ AuthDatabaseOptions.cs # Authentication database settings
โโโ Interfaces/ # Service and repository contracts
โ โโโ IUserRepository.cs # User repository interface (handles all user-related data)
โ โโโ IRoleRepository.cs # Role repository interface (handles all role-related data)
โ โโโ IUserProvider.cs # User provider interface
โ โโโ IRoleProvider.cs # Role provider interface
โ โโโ IUserClaimProvider.cs # User claim provider interface
โ โโโ IRoleClaimProvider.cs # Role claim provider interface
โ โโโ IUserLoginProvider.cs # User login provider interface
โ โโโ IUserRoleProvider.cs # User role provider interface
โ โโโ IUserTokenProvider.cs # User token provider interface
โ โโโ IAuthenticationDatabaseService.cs # Database service interface
โโโ Extensions/ # Service collection extensions
โโโ ServiceCollectionExtensions.cs # DI container configuration
โโโ IdentityBuilderExtensions.cs # Identity builder configuration
Data Flow
- Controllers/Handlers โ Providers โ Repositories โ Database
- Providers handle business logic and orchestrate repository operations
- Repositories execute SQL queries using query constants with automatic transaction management
- Query Constants provide maintainable SQL definitions
Note: The library uses a consolidated repository pattern where:
UserRepository
handles all user-related operations (users, claims, logins, roles, tokens)RoleRepository
handles all role-related operations (roles, role claims)- This design provides better transaction management and reduces complexity compared to separate repositories for each entity type
Transaction Management
- Automatic Transactions: Each transaction method manages its own transaction lifecycle
- Resource Safety: Using
using var transaction
ensures proper disposal - Exception Handling: Automatic rollback on errors with clean exception propagation
- No Shared State: Each method is completely self-contained
๐ฏ Key Benefits
1. Query Constants Pattern
Instead of stored procedures or embedded SQL files, queries are defined as C# constants:
public static class AspNetIdentityQueries
{
public const string Users_GetAll = @"
SELECT [Id], [UserName], [NormalizedUserName], [Email], [NormalizedEmail],
[EmailConfirmed], [PasswordHash], [SecurityStamp], [ConcurrencyStamp],
[PhoneNumber], [PhoneNumberConfirmed], [TwoFactorEnabled], [LockoutEnd],
[LockoutEnabled], [AccessFailedCount]
FROM [dbo].[AspNetUsers]
ORDER BY [UserName]";
}
Advantages:
- Version Control: Queries are tracked in source control
- Type Safety: Compile-time validation of SQL syntax
- Maintainability: Easy to refactor and update queries
- Performance: No runtime file loading or parsing overhead
2. Repository Pattern
Clean abstraction layer between business logic and data access using a consolidated approach:
public class UserRepository : IUserRepository
{
// User operations
public async Task<ApplicationUser?> GetApplicationUserById(string? userId)
{
return await dataAccess.LoadFirst<ApplicationUser, dynamic>(
AspNetIdentityQueries.Users_GetById,
new { Id = userId },
commandType: CommandType.Text,
connection.ConnectionName!);
}
// User claim operations
public async Task<Guid> CreateUserClaimInTransaction(UserClaim entity)
{
using var transaction = dataAccess.StartTransaction(connection.ConnectionName!);
try
{
await dataAccess.SaveDataInTransaction(AspNetIdentityQueries.UserClaims_Insert,
entity,
transaction,
CommandType.Text);
dataAccess.CommitTransaction(transaction);
return entity.Id;
}
catch
{
dataAccess.RollbackTransaction(transaction);
throw;
}
}
// User login, role, and token operations are also handled here
// This consolidated approach provides better transaction management
}
Benefits of Consolidated Repositories:
- Simplified Transaction Management: All related operations can be wrapped in single transactions
- Reduced Complexity: Fewer repository classes to maintain and inject
- Better Performance: Fewer database connections and transaction overhead
- Consistent Patterns: Same data access patterns across all user-related operations
3. Modern Transaction Pattern
Automatic transaction management using the using
pattern for better resource management:
public async Task<Guid> CreateUserClaimInTransaction(UserClaim entity)
{
using var transaction = dataAccess.StartTransaction(connection.ConnectionName!);
try
{
await dataAccess.SaveDataInTransaction(AspNetIdentityQueries.UserClaims_Insert,
entity,
transaction,
CommandType.Text);
dataAccess.CommitTransaction(transaction);
return entity.Id;
}
catch
{
dataAccess.RollbackTransaction(transaction);
throw;
}
}
Benefits:
- Automatic Resource Management: Transactions are disposed automatically
- Exception Safety: Automatic rollback on errors
- Cleaner Code: No manual transaction state management
- Consistent Pattern: Same approach used across all repositories
4. Identity Store Integration
Custom ASP.NET Core Identity stores for flexible data access:
// Custom UserStore implementation
public class UserStore : IUserStore<ApplicationUser>, IUserEmailStore<ApplicationUser>
{
private readonly IUserRepository _userRepository;
public async Task<ApplicationUser?> FindByIdAsync(string userId, CancellationToken cancellationToken)
{
return await _userRepository.GetApplicationUserById(userId);
}
// ... other Identity store methods
}
5. Updated Provider Pattern
Providers now work seamlessly with the new transaction pattern:
// RoleProvider automatically uses the new transaction pattern
public async Task<IdentityResult> UpdateApplicationRole(ApplicationRole role)
{
try
{
await _roleRepository.UpdateApplicationRoleInTransaction(role);
// Claims are automatically handled in transactions
// No manual transaction management needed
return IdentityResult.Success;
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed updating application role");
return IdentityResult.Failed(new IdentityError { ... });
}
}
6. Extension Methods
Easy service configuration and Identity setup:
// In Program.cs or Startup.cs
services.AddInfrastructureAuthentication(options =>
{
options.ConnectionString = configuration.GetConnectionString("DefaultConnection");
options.DbSchema = "dbo";
});
// Configure Identity with custom stores
services.AddDefaultIdentity<ApplicationUser>()
.AddRoles<ApplicationRole>()
.AddInfrastructureStores();
๐ Recent Improvements & Bug Fixes
AuthenticationDatabaseService Enhancements
- File System Abstraction: Replaced
File.Exists()
withIDocumentService.FileExists()
for better testability - Null Path Handling: Added proper null checking for file paths to prevent runtime errors
- Bug Fix: Fixed
GetUser
method returningnull
instead of existing user when user already exists
Provider Pattern Improvements
- Exception Safety: All providers now throw
ArgumentNullException
instead ofNullReferenceException
- Consistent Validation: Standardized null checking across all provider methods
- Better Error Messages: Clear, actionable error messages for debugging
Test Infrastructure
- Moq Setup: Resolved all Moq setup issues with proper mocking patterns
- Configuration Testing: Real configuration objects instead of complex mocking for better test reliability
- Interface Validation: Comprehensive testing of interface contracts and method signatures
๐ Migration from Stored Procedures
This library has been migrated from a stored procedure-based approach to a modern query constants pattern. This migration provides several benefits:
What Changed
- Before: 31 stored procedures for ASP.NET Core Identity operations
- After: SQL queries defined as C# constants in
AspNetIdentityQueries.cs
- Transaction Management: Moved from manual
BeginTransaction/CommitTransaction/RollbackTransaction
to automaticusing var transaction
pattern
Migration Benefits
- Better Version Control: SQL queries are now tracked in source control
- Easier Testing: Queries can be unit tested independently
- Improved Performance: No stored procedure compilation overhead
- Better Maintainability: Queries are co-located with repository code
- Type Safety: Compile-time validation of SQL syntax
Example Migration
Before (Stored Procedures)
// Old approach using stored procedures
return await dataAccess.LoadData<ApplicationUser, dynamic>(
$"{_options.DbSchema}.sp_AspNetUsers_GetAll",
new { },
commandType: CommandType.StoredProcedure,
_connection.ConnectionName);
After (Query Constants)
// New approach using query constants
return await dataAccess.LoadData<ApplicationUser, dynamic>(
AspNetIdentityQueries.Users_GetAll,
new { },
commandType: CommandType.Text,
connection.ConnectionName!);
Migration Benefits
- Eliminates stored procedure maintenance
- Better version control and deployment
- Easier testing and debugging
- Consistent with modern development practices
๐ง Installation & Setup
Package Reference
<PackageReference Include="CG.Infrastructure.Authentication" Version="3.10.0" />
Service Registration
// Program.cs or Startup.cs
// Repository registrations
services.AddScoped<IUserRepository, UserRepository>();
services.AddScoped<IRoleRepository, RoleRepository>();
// Provider registrations
services.AddScoped<IUserProvider, UserProvider>();
services.AddScoped<IRoleProvider, RoleProvider>();
services.AddScoped<IUserClaimProvider, UserClaimProvider>();
services.AddScoped<IRoleClaimProvider, RoleClaimProvider>();
services.AddScoped<IUserLoginProvider, UserLoginProvider>();
services.AddScoped<IUserRoleProvider, UserRoleProvider>();
services.AddScoped<IUserTokenProvider, UserTokenProvider>();
// Service registrations
services.AddScoped<IAuthenticationDatabaseService, AuthenticationDatabaseService>();
// Identity store registrations
services.AddScoped<IUserStore<ApplicationUser>, UserStore>();
services.AddScoped<IRoleStore<ApplicationRole>, RoleStore>();
Configuration
services.Configure<AuthDatabaseOptions>(configuration.GetSection("ConfigOptions"));
services.Configure<ConnectionOptions>(configuration.GetSection("ConnectionStrings"));
๐ Usage Examples
User Management
public class UserController : ControllerBase
{
private readonly IUserProvider _userProvider;
public UserController(IUserProvider userProvider)
{
_userProvider = userProvider;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<ApplicationUser>>> GetUsers()
{
var users = await _userProvider.GetAllApplicationUsers();
return Ok(users);
}
[HttpPost]
public async Task<ActionResult> CreateUser([FromBody] ApplicationUser user)
{
var result = await _userProvider.CreateApplicationUser(user);
if (result.Succeeded)
return CreatedAtAction(nameof(GetUsers), user);
return BadRequest(result.Errors);
}
}
Role Management
public class RoleController : ControllerBase
{
private readonly IRoleProvider _roleProvider;
public RoleController(IRoleProvider roleProvider)
{
_roleProvider = roleProvider;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<ApplicationRole>>> GetRoles()
{
var roles = await _roleProvider.GetAllApplicationRoles();
return Ok(roles);
}
}
Custom Queries
// Add custom queries to AspNetIdentityQueries.cs
public const string Users_GetByDepartment = @"
SELECT u.* FROM [dbo].[AspNetUsers] u
INNER JOIN [dbo].[UserDepartments] ud ON u.Id = ud.UserId
WHERE ud.DepartmentId = @DepartmentId";
// Use in repository
public async Task<IReadOnlyList<ApplicationUser>> GetUsersByDepartment(int departmentId)
{
return await dataAccess.LoadData<ApplicationUser, dynamic>(
AspNetIdentityQueries.Users_GetByDepartment,
new { DepartmentId = departmentId },
connection.ConnectionName!,
CommandType.Text);
}
Transaction Operations with New Pattern
// Create user claim with automatic transaction management
var userClaim = new UserClaim
{
ClaimType = "Permission",
ClaimValue = "Read",
UserId = "user123"
};
var claimId = await userRepository.CreateUserClaimInTransaction(userClaim);
// Transaction is automatically managed - no manual Begin/Commit/Rollback needed
// Update user with claims, logins, and roles
var result = await userProvider.UpdateApplicationUser(user);
// All operations are automatically wrapped in transactions by the repository methods
๐๏ธ Database Schema
The library works with standard ASP.NET Core Identity tables:
- AspNetUsers: User accounts and authentication data
- AspNetRoles: Application roles
- AspNetUserRoles: User-role relationships
- AspNetUserClaims: User-specific claims
- AspNetRoleClaims: Role-specific claims
- AspNetUserLogins: External login providers
- AspNetUserTokens: User authentication tokens
๐งช Testing
Current Test Status
โ All 242 tests are passing with comprehensive coverage of:
- Interface contract validation
- Provider business logic
- Repository data access patterns
- Service orchestration
- Configuration and dependency injection
Code Quality Improvements
- CA2263 Warnings Resolved: All code analysis warnings have been addressed
- Null Safety: Comprehensive null reference handling throughout the codebase
- Moq Setup: Clean, maintainable test mocking patterns
- Exception Handling: Proper ArgumentNullException throwing instead of NullReferenceException
Unit Testing Repositories
[Fact]
public async Task GetApplicationUserById_WithValidId_ReturnsUser()
{
// Arrange
var mockDataAccess = new Mock<IDataAccess>();
var mockConnection = new Mock<ConnectionOptions>();
var repository = new UserRepository(mockDataAccess.Object, mockConnection.Object);
var expectedUser = new ApplicationUser { Id = "test-id", UserName = "testuser" };
mockDataAccess.Setup(x => x.LoadFirst<ApplicationUser, dynamic>(
AspNetIdentityQueries.Users_GetById,
It.IsAny<dynamic>(),
CommandType.Text,
It.IsAny<string>()))
.ReturnsAsync(expectedUser);
// Act
var result = await repository.GetApplicationUserById("test-id");
// Assert
Assert.Equal(expectedUser, result);
}
Integration Testing
[Fact]
public async Task CreateApplicationUser_WithValidData_SavesToDatabase()
{
// Arrange
var user = new ApplicationUser
{
Id = "test-id",
UserName = "testuser",
Email = "test@example.com"
};
// Act
var result = await _userProvider.CreateApplicationUser(user);
// Assert
Assert.True(result.Succeeded);
var savedUser = await _userProvider.GetApplicationUserById(Guid.Parse(user.Id));
Assert.NotNull(savedUser);
}
๐จ Error Handling
Null Safety
The library includes comprehensive null safety with proper exception handling:
// Null coalescing for claim values
return [.. claims.Select(s => new Claim(
s.ClaimType ?? string.Empty,
s.ClaimValue ?? string.Empty))];
// Null checks before operations with proper exceptions
ArgumentNullException.ThrowIfNull(user);
if (user != null && entity.Role != null)
{
await CreateRole(entity.Role);
await AddUserToRole(user, entity.Role);
}
// File path null safety
if (string.IsNullOrEmpty(_usersPath) || !_documentService.FileExists(_usersPath))
{
// Handle case where no file path is configured
}
Transaction Rollback
try
{
_userRepository.BeginTransaction();
// ... operations
_userRepository.CommitTransaction();
}
catch (Exception ex)
{
_userRepository.RollbackTransaction();
_logger.LogError(ex, "Operation failed and was rolled back");
throw;
}
๐ Security Considerations
- Parameterized Queries: All SQL queries use parameterized inputs to prevent SQL injection
- Input Validation: Comprehensive validation of user inputs
- Transaction Isolation: Proper transaction isolation levels for concurrent operations
- Audit Trail: Built-in logging for security-related operations
๐ Dependencies
Core Framework
- .NET 9.0: Target framework
CG Infrastructure Libraries
- CG.Infrastructure.Configuration (3.9.2): Configuration management and options
- CG.Infrastructure.Core (3.9.0): Core infrastructure components
- CG.Infrastructure.Data (3.9.6): Data access and persistence abstractions
- CG.Infrastructure.Entity (3.10.1): Entity framework and data modeling
- CG.Infrastructure.Services (3.9.1): Service layer infrastructure
Identity & Authentication
- Microsoft.Extensions.Identity.Core (9.0.2): ASP.NET Core Identity core functionality
- Microsoft.Extensions.Identity.Stores (9.0.2): Identity data stores and persistence
- Duende.IdentityServer (7.1.0): OpenID Connect and OAuth 2.0 server
- Duende.IdentityServer.AspNetIdentity (7.1.0): IdentityServer integration with ASP.NET Core Identity
Utilities
- AutoMapper (14.0.0): Object-to-object mapping library
๐ค Contributing
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
Development Guidelines
- Follow C# coding conventions
- Add unit tests for new functionality
- Update documentation for API changes
- Ensure null safety in all public methods
- Use query constants for all SQL operations
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.
๐ Support
- Documentation: This README and inline code comments
- Issues: Create an issue in the project repository
- Discussions: Use GitHub Discussions for questions and ideas
- Email: Contact the development team directly
๐ฎ Roadmap
- Code Quality: All CA2263 warnings resolved
- Test Coverage: 242/242 tests passing
- Null Safety: Comprehensive null reference handling implemented
- Exception Handling: Proper ArgumentNullException patterns
- Performance Optimization: Query performance analysis and optimization
- Caching Layer: Redis integration for frequently accessed data
- Audit Logging: Comprehensive audit trail for all operations
- Multi-tenancy: Support for multi-tenant applications
- GraphQL Support: GraphQL endpoint for flexible data querying
- Event Sourcing: Event-driven architecture for complex workflows
Built with โค๏ธ by the CG Infrastructure Team
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
- AutoMapper (>= 15.0.1)
- CG.Infrastructure.Configuration (>= 3.10.1)
- CG.Infrastructure.Core (>= 3.10.8)
- CG.Infrastructure.Data (>= 3.10.9)
- CG.Infrastructure.Entity (>= 3.10.1)
- CG.Infrastructure.Services (>= 3.10.6)
- Duende.IdentityServer (>= 7.3.1)
- Duende.IdentityServer.AspNetIdentity (>= 7.3.1)
- Microsoft.Extensions.Identity.Core (>= 9.0.8)
- Microsoft.Extensions.Identity.Stores (>= 9.0.8)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on CG.Infrastructure.Authentication:
Package | Downloads |
---|---|
CG.Infrastructure.Identity
Infra Identity library with Duende setup, extensions and database contexts |
GitHub repositories
This package is not used by any popular GitHub repositories.