赞
踩
审计跟踪对于跟踪数据变化、维护安全性规至关重要。在本文中,我们将在 ASP.NET Core Web API 中实现审计跟踪。该示例将涵盖从设置项目到执行 CRUD 操作和验证审计日志的所有内容。
打开终端或命令提示符并运行以下命令来创建一个新的 ASP.NET Core Web API 项目:
dotnet new webapi -n AuditTrailExample
cd AuditTrailImplementtionInAspNetCoreWebAPI
安装 Entity Framework Core 和 SQL Server 必要的包。
dotnet add package Microsoft.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Tools
dotnet add package Microsoft.AspNetCore.Http.Abstractions
创建产品和审计日志实体。
创建一个新的文件夹 Models 并添加 Product 类。
namespace AuditTrailImplementtionInAspNetCoreWebAPI.Model
{
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public int Stock { get; set; }
}
}
添加 AuditLog 类。
namespace AuditTrailImplementtionInAspNetCoreWebAPI.Model
{
public class AuditLog
{
public int Id { get; set; }
public string? UserId { get; set; }
public DateTime Timestamp { get; set; }
public string? Action { get; set; }
public string? TableName { get; set; }
public string? RecordId { get; set; }
public string? Changes { get; set; }
}
}
创建新文件夹Data并添加ApplicationDbContext类:
using AuditTrailImplementtionInAspNetCoreWebAPI.Model; using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore; using System.Security.Claims; using System.Collections.Generic; namespace AuditTrailImplementtionInAspNetCoreWebAPI.Data { public class ApplicationDbContext : DbContext { private readonly IHttpContextAccessor _httpContextAccessor; public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options, IHttpContextAccessor httpContextAccessor) : base(options) { _httpContextAccessor = httpContextAccessor; } public DbSet<AuditLog> AuditLogs { get; set; } public DbSet<Product> Products { get; set; } public override int SaveChanges() { var auditEntries = OnBeforeSaveChanges(); var result = base.SaveChanges(); OnAfterSaveChanges(auditEntries); return result; } private List<AuditEntry> OnBeforeSaveChanges() { ChangeTracker.DetectChanges(); var auditEntries = new List<AuditEntry>(); var userId = _httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier); foreach (var entry in ChangeTracker.Entries()) { if (entry.Entity is AuditLog || entry.State == EntityState.Detached || entry.State == EntityState.Unchanged) { continue; } var auditEntry = new AuditEntry(entry) { TableName = entry.Entity.GetType().Name, Action = entry.State.ToString(), UserId = "1234" }; auditEntries.Add(auditEntry); foreach (var property in entry.Properties) { string propertyName = property.Metadata.Name; if (property.IsTemporary) { auditEntry.TemporaryProperties.Add(property); continue; } if (entry.State == EntityState.Added) { auditEntry.NewValues[propertyName] = property.CurrentValue; } else if (entry.State == EntityState.Deleted) { auditEntry.OldValues[propertyName] = property.OriginalValue; } else if (entry.State == EntityState.Modified && property.IsModified) { auditEntry.OldValues[propertyName] = property.OriginalValue; auditEntry.NewValues[propertyName] = property.CurrentValue; } } } foreach (var auditEntry in auditEntries.Where(e => !e.HasTemporaryProperties)) { AuditLogs.Add(auditEntry.ToAuditLog()); } return auditEntries.Where(e => e.HasTemporaryProperties).ToList(); } private void OnAfterSaveChanges(List<AuditEntry> auditEntries) { if (auditEntries == null || auditEntries.Count == 0) { return; } foreach (var auditEntry in auditEntries) { foreach (var prop in auditEntry.TemporaryProperties) { if (prop.Metadata.IsPrimaryKey()) { auditEntry.KeyValues[prop.Metadata.Name] = prop.CurrentValue; } else { auditEntry.NewValues[prop.Metadata.Name] = prop.CurrentValue; } } AuditLogs.Add(auditEntry.ToAuditLog()); } SaveChanges(); } } }
在 appsettings.json 中,将连接字符串添加到您的 SQL Server:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"ConnectionStrings": {
"DefaultConnection": "Server=SARDAR-MUDASSAR\\SQLEXPRESS2022;database=AuditLog;User ID=sa;Password=Smak$95;Trusted_Connection=True;MultipleActiveResultSets=true;TrustServerCertificate=True"
},
"AllowedHosts": "*"
}
更新 Program.cs 文件以配置服务和中间件:
using AuditTrailImplementtionInAspNetCoreWebAPI.Data; using Microsoft.EntityFrameworkCore; namespace AuditTrailImplementtionInAspNetCoreWebAPI { public class Program { public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"))); builder.Services.AddControllers(); builder.Services.AddHttpContextAccessor(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run(); } } }
创建一个 Controllers 文件夹并添加 ProductsController 类。
using AuditTrailImplementtionInAspNetCoreWebAPI.Data; using AuditTrailImplementtionInAspNetCoreWebAPI.Model; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using System.Threading.Tasks; namespace AuditTrailImplementtionInAspNetCoreWebAPI.Controllers { [ApiController] [Route("[controller]")] public class ProductsController : ControllerBase { private readonly ApplicationDbContext _context; public ProductsController(ApplicationDbContext context) { _context = context; } [HttpGet] public async Task<IActionResult> GetProducts() { var products = await _context.Products.ToListAsync(); return Ok(products); } [HttpGet("{id}")] public async Task<IActionResult> GetProduct(int id) { var product = await _context.Products.FindAsync(id); if (product == null) { return NotFound(); } return Ok(product); } [HttpPost] public async Task<IActionResult> CreateProduct([FromBody] Product newProduct) { _context.Products.Add(newProduct); await _context.SaveChangesAsync(); return CreatedAtAction(nameof(GetProduct), new { id = newProduct.Id }, newProduct); } [HttpPut("{id}")] public async Task<IActionResult> UpdateProduct(int id, [FromBody] Product updatedProduct) { var product = await _context.Products.FindAsync(id); if (product == null) { return NotFound(); } product.Name = updatedProduct.Name; product.Price = updatedProduct.Price; product.Stock = updatedProduct.Stock; await _context.SaveChangesAsync(); return NoContent(); } [HttpDelete("{id}")] public async Task<IActionResult> DeleteProduct(int id) { var product = await _context.Products.FindAsync(id); if (product == null) { return NotFound(); } _context.Products.Remove(product); await _context.SaveChangesAsync(); return NoContent(); } } }
生成迁移文件并更新数据库。
add migration IMAuditTrail22042024
Update-database
使用 API 执行 CRUD 操作并验证 AuditLogs 表是否填充了适当的条目。
curl -X POST "https://localhost:5001/products" -H "accept: text/plain" -H "Content-Type: application/json" -d "{ \"name\": \"New Product\", \"price\": 19.99, \"stock\": 100 }"
curl -X PUT "https://localhost:5001/products/1" -H "accept: text/plain" -H "Content-Type: application/json" -d "{ \"name\": \"Updated Product\", \"price\": 29.99, \"stock\": 150 }"
curl -X DELETE "https://localhost:5001/products/1" -H "accept: text/plain"
执行上述操作后,检查数据库中的 AuditLogs 表,确保其中填充了预期的条目。
通过遵循此端到端示例,您已成功在 ASP.NET Core Web API 中实现了审计跟踪。此实现有助于跟踪数据的变化,这对于维护安全性、合规性和调试问题至关重要。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。