Asp.net core 使用Serilog和Asp.Net Core时将用户添加到日志上下文
我正在尝试将Serilog与我的ASP.NETCore1.0项目结合使用。我似乎无法将当前登录的用户添加到已登录的属性中 有人知道了吗 我试过这个:Asp.net core 使用Serilog和Asp.Net Core时将用户添加到日志上下文,asp.net-core,serilog,Asp.net Core,Serilog,我正在尝试将Serilog与我的ASP.NETCore1.0项目结合使用。我似乎无法将当前登录的用户添加到已登录的属性中 有人知道了吗 我试过这个: using System.Threading.Tasks; using Serilog.Context; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using System.Security.Claims; using xxx.Models; name
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>();
}
}
}
但这总是以“匿名”作为用户名结束
提前谢谢
Søren Rokkedal您需要在如下块中调用
\u 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);
}
}
我只需要几行代码就可以获得经过身份验证的Active Directory用户。我在核心身份验证方面不是很有经验,尤其是在声明方面,但这可能会让你走上正轨,或者至少会帮助其他人解决与你类似的问题,但与AD有关的问题 关键行是
Enrich.FromLogContext()
和app.Use(异步…
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>
您的中间件可能很好。但配置中间件的顺序很重要。您的EnricLogger中间件是第一个。这意味着它在身份验证中间件之前运行。将
app.EnricLogger
调用移动到添加身份验证中间件的正下方(可能是app.UseAuthentication
)。这样,当EnricLogger中间件运行时,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>();
});
...
}
public void配置服务(IServiceCollection服务)
{
services.addScope();
services.AddMvc(o=>
{
o、 Filters.Add();
});
...
}
在LoggerConfiguration
对象上使用丰富.WithEnvironmentUserName()
方法,例如:
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();
公共静态IWebHost BuildWebHost(字符串[]args)=>
WebHost.CreateDefaultBuilder(args)
.ConfigureLogging((hostingContext,config)=>
{
config.ClearProviders();
})
.UseStartup()
.useserlog((ctx,cfg)=>
{
cfg.ReadFrom.Configuration(ctx.Configuration)
.Enrich.WithEnvironmentUserName()
})
.Build();
我在web.config中也有以下设置,尽管我还没有证明所有IIS服务器上是否都需要:
您尝试过在身份验证后将其添加到管道中吗?不确定这是什么意思我的意思是调用app.enrichloger();
调用app.UseAuthentication(..);
,或者不管您的身份验证方法是什么。您在对用户进行身份验证之前过早地在管道中注入记录器,因此它将始终是匿名的。我有app.UseIdentity()在我呼吁丰富logger@SørenRokkedal..感谢这是一篇老帖子,但你有没有发现这一点?谢谢你的回复。我相信最初的帖子包含了wait_next(httpContext)。实现建议的解决方案无法使其正常工作。每次调用Invoke方法时,httpContext.User.Identity.IsAuthenticated都是错误的。有什么想法吗?感谢您的后续行动。那么对此不确定。您有Enrich.FromLogContext()吗
设置您的日志配置
?是的,我已将其配置为所示的名称,WithEnvironmentUserName
将从环境变量获取用户-因此它将获取服务器的用户名,而不是当前web app用户的用户名。您对中间件方法提出了一些有效的观点,但用户名不是这种方法在任何地方都可以使用-例如,它不是为Microsoft.AspNetCore.Hosting
,Microsoft.AspNetCore.Mvc.ViewFeatures
,Microsoft.AspNetCore.Routing.EndpointMiddleware
和许多其他方法记录的
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();