Sør*_*dal 13 serilog asp.net-core
我正在尝试将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>();
}
}
}
Run Code Online (Sandbox Code Playgroud)
我通过添加以下命令在Startup.cs中触发:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
loggerFactory.AddSerilog();
app.EnrichLogger();
...
}
Run Code Online (Sandbox Code Playgroud)
但这最终会以"匿名"作为用户名.
提前致谢
SørenRokkedal
我只需几行代码即可获得经过身份验证的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();
});
}
}
Run Code Online (Sandbox Code Playgroud)
对于通过IIS/Kestrel进行AD身份验证,web.config需要forwardWindowsAuthToken如下设置:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<aspNetCore ... forwardWindowsAuthToken="true" />
</system.webServer>
</configuration>
Run Code Online (Sandbox Code Playgroud)
你的中间件可能没问题。但是配置中间件的顺序很重要。您的 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)
{
}
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以使用 DI 全局应用您的过滤器。在您的 Services.cs 文件中:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<LogEnrichmentFilter>();
services.AddMvc(o =>
{
o.Filters.Add<LogEnrichmentFilter>();
});
...
}
Run Code Online (Sandbox Code Playgroud)
您需要_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);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5464 次 |
| 最近记录: |