我正在尝试将Serilog与我的ASP.Net Core 1.0项目一起使用。我似乎无法将当前登录的用户添加到已记录的属性中。
有人想出来吗?
我试过这个:
using System.Threading.Tasks;
using Serilog.Context;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using System.Security.Claims;
using xxx.Models;
namespace xxx.Utils
{
public class EnrichSerilogContextMiddleware
{
private readonly RequestDelegate _next;
public EnrichSerilogContextMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext httpContext)
{
var username = httpContext.User.Identity.Name;
if (httpContext.User.Identity.IsAuthenticated)
{
var userFullName = (((ClaimsIdentity)httpContext.User.Identity).FindFirst(Member.FullnameClaimName).Value);
var userName = "anyone@gmail.com";
LoggerEnricher.AddEntryPointContext(userFullName, userName);
}
else
{
LoggerEnricher.AddEntryPointContext();
}
await _next(httpContext);
}
}
public static class LoggerEnricher
{
public static void AddEntryPointContext(string userFullName = null, string username = null)
{
if (!string.IsNullOrWhiteSpace(username) || !string.IsNullOrWhiteSpace(userFullName))
{
LogContext.PushProperty("Username", username);
LogContext.PushProperty("UserFullename", userFullName);
}
else
{
LogContext.PushProperty("Username", "Anonymous");
}
}
public static void EnrichLogger(this IApplicationBuilder app)
{
app.UseMiddleware<EnrichSerilogContextMiddleware>();
}
}
}
我通过添加:
在Startup.cs中触发此操作 public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
loggerFactory.AddSerilog();
app.EnrichLogger();
...
}
但是这总是以“匿名”作为用户名。
提前致谢
SørenRokkedal答案 0 :(得分:6)
我只需几行代码即可获得经过身份验证的Active Directory用户。我对Core身份验证没有太多经验,尤其是声称,但是这可能会让你走上正轨,或者至少帮助那些带有类似问题的人,而不是AD。
关键行是Enrich.FromLogContext()
和app.Use(async...
public class Startup
{
public IConfigurationRoot Configuration { get; }
public Startup(IHostingEnvironment env)
{
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext() // Populates a 'User' property on every log entry
.WriteTo.MSSqlServer(Configuration.GetConnectionString("MyDatabase"), "Logs")
.CreateLogger();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.WithFilter(new FilterLoggerSettings
{
{ "Default", LogLevel.Information },
{ "Microsoft", LogLevel.Warning },
{ "System", LogLevel.Warning }
})
.AddSerilog();
app.Use(async (httpContext, next) =>
{
var userName = httpContext.User.Identity.IsAuthenticated ? httpContext.User.Identity.Name : "unknown";
LogContext.PushProperty("User", !String.IsNullOrWhiteSpace(userName) ? userName : "unknown");
await next.Invoke();
});
}
}
对于通过IIS / Kestrel进行AD身份验证,web.config需要forwardWindowsAuthToken
设置,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<aspNetCore ... forwardWindowsAuthToken="true" />
</system.webServer>
</configuration>
答案 1 :(得分:3)
您需要在块中调用_next
,如下所示:
public async Task Invoke(HttpContext httpContext)
{
if (httpContext.User.Identity.IsAuthenticated)
{
var userFullName = (((ClaimsIdentity)httpContext.User.Identity).FindFirst(Member.FullnameClaimName).Value);
var userName = "anyone@gmail.com";
using (LogContext.PushProperty("Username", userName))
using (LogContext.PushProperty("UserFullName", userFullName))
{
await _next(httpContext);
}
}
else
{
await _next(httpContext);
}
}
答案 2 :(得分:2)
你的中间件可能很好。但是配置中间件的顺序很重要。您的EnrichLogger中间件是第一个。这意味着它在认证中间件之前运行。将app.EnrichLogger
调用移到您添加身份验证中间件(可能是app.UseAuthentication
)的下方。这样,当您的EnrichLogger中间件运行时,将正确设置HttpContext.User属性。
<强>更新强>
实际上,即使将此中间件移到认证中间件下面也可能还不够。似乎可以在MVC中间件内设置身份(至少在某些配置中)。这意味着在执行控制器操作之后(通过在MVC中间件之后将其移动),您无法从中间件访问用户标识。但是,在日志中使用它将为时已晚。
相反,您可能必须使用MVC过滤器将用户信息添加到日志上下文中。例如,您可以创建一个这样的过滤器:
public class LogEnrichmentFilter : IActionFilter
{
private readonly IHttpContextAccessor _httpContextAccessor;
public LogEnrichmentFilter(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public void OnActionExecuting(ActionExecutingContext context)
{
var httpContext = _httpContextAccessor.HttpContext;
if (httpContext.User.Identity.IsAuthenticated)
{
LogContext.PushProperty("Username", httpContext.User.Identity.Name);
}
else
{
LogContext.PushProperty("Username", "Anonymous");
}
}
public void OnActionExecuted(ActionExecutedContext context)
{
}
}
然后,您可以使用DI全局应用过滤器。在Services.cs文件中:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<LogEnrichmentFilter>();
services.AddMvc(o =>
{
o.Filters.Add<LogEnrichmentFilter>();
});
...
}
答案 3 :(得分:-3)
在.Enrich.WithEnvironmentUserName()
对象上使用LoggerConfiguration
方法,例如:
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureLogging((hostingContext, config) =>
{
config.ClearProviders();
})
.UseStartup<Startup>()
.UseSerilog((ctx, cfg) =>
{
cfg.ReadFrom.Configuration(ctx.Configuration)
.Enrich.WithEnvironmentUserName()
})
.Build();
我在web.config中也有以下设置,虽然我没有证明是否在所有IIS服务器上都需要它:
<system.webServer><aspNetCore ... forwardWindowsAuthToken="true"> ...