| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- using SharedKernel.Constants;
- using Application.Abstractions.Data;
- using Domain.Entities.Director;
- using System.Diagnostics;
- namespace Admin.Middlewares;
- public class AdminAccessLogMiddleware(RequestDelegate next)
- {
- // 로깅 제외 경로
- private static readonly string[] ExcludePrefixes =
- [
- "/lib/",
- "/css/",
- "/js/",
- "/images/",
- "/favicon",
- "/_framework",
- "/_blazor",
- "/.well-known/",
- "/Identity/Account"
- ];
- // 로깅 제외 확장자
- private static readonly string[] ExcludeExtensions =
- [
- ".css",
- ".js",
- ".map",
- ".png",
- ".jpg",
- ".jpeg",
- ".gif",
- ".svg",
- ".ico",
- ".woff",
- ".woff2",
- ".ttf",
- ".eot"
- ];
- public async Task InvokeAsync(HttpContext context)
- {
- var path = context.Request.Path.Value ?? "";
- // 정적 파일, Identity 페이지 제외
- if (ShouldSkip(path))
- {
- await next(context);
- return;
- }
- // 인증되지 않은 사용자 제외
- if (context.User.Identity is not { IsAuthenticated: true })
- {
- await next(context);
- return;
- }
- var sw = Stopwatch.StartNew(); // 시작 시간
- await next(context);
- sw.Stop(); // 종료 시간
- try
- {
- var db = context.RequestServices.GetRequiredService<IAppDbContext>();
- var userID = context.User.Identity.Name ?? "-";
- var userName = context.User.FindFirst(System.Security.Claims.ClaimTypes.GivenName)?.Value;
- var method = context.Request.Method;
- var queryString = context.Request.QueryString.HasValue ? context.Request.QueryString.Value : null;
- var statusCode = context.Response.StatusCode;
- var elapsedMs = sw.ElapsedMilliseconds;
- var menuName = ResolveMenuName(path);
- var ipAddress = context.Connection.RemoteIpAddress?.ToString();
- var userAgent = context.Request.Headers.UserAgent.ToString();
- var log = AdminAccessLog.Create(
- userID,
- userName,
- method,
- path,
- queryString,
- statusCode,
- elapsedMs,
- menuName,
- ipAddress,
- userAgent);
- await db.AdminAccessLog.AddAsync(log);
- await db.SaveChangesAsync();
- }
- catch
- {
- }
- }
- // 로깅 제외 경로 및 확장자 확인
- private static bool ShouldSkip(string path)
- {
- foreach (var prefix in ExcludePrefixes)
- {
- if (path.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- }
- foreach (var ext in ExcludeExtensions)
- {
- if (path.EndsWith(ext, StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- }
- return false;
- }
- // 경로에 해당하는 메뉴 이름 찾기
- private static string? ResolveMenuName(string path)
- {
- var menus = Menus.GetMenus();
- return FindMenuName(menus, path.TrimEnd('/'));
- }
- // 재귀적으로 메뉴 트리 탐색
- private static string? FindMenuName(List<Menu> menus, string path)
- {
- foreach (var menu in menus)
- {
- if (!string.IsNullOrEmpty(menu.Path))
- {
- var menuPath = menu.Path.TrimEnd('/');
- if (path.Equals(menuPath, StringComparison.OrdinalIgnoreCase) || path.StartsWith(menuPath + "/", StringComparison.OrdinalIgnoreCase))
- {
- return menu.Name;
- }
- }
- if (menu.Children is { Count: > 0 })
- {
- var childResult = FindMenuName(menu.Children, path);
- if (childResult is not null)
- {
- return childResult;
- }
- }
- }
- return null;
- }
- }
|