由于使用了不同的认证方式,可能会导致 NLog 的 ${aspnet-user-identity} 拿不到值,从而写入的是空白,谁知道他里面是怎么解析的呢?之前使用 NLog 的配置可能如下
<targets async="true">
<target name="fileTarget" xsi:type="File" fileName="..\logs\${shortdate}.txt"
layout="${longdate} ${uppercase:${level}} ${aspnet-user-identity} ${aspnet-TraceIdentifier} ${callsite} ${message}"
archiveFileName="..\logs\${shortdate}.{#}.txt" archiveEvery="Day" archiveNumbering="Rolling"
maxArchiveFiles="60" concurrentWrites="true" keepFileOpen="false" />
<!--layout="${longdate} ${aspnet-user-identity} ${ndlc:bottomFrames=0:topFrames=1} ${aspnet-TraceIdentifier:ignoreActivityId=false} ${uppercase:${level}} ${logger} ${message}"-->
<target name="dbTarget"
xsi:type="Database"
dbProvider="sqlserver"
connectionString="${configsetting:name=ConnectionStrings.Default}"
keepConnection="true"
commandType="StoredProcedure"
commandText="[dbo].[usp_AddLog]">
<parameter name="@machineName" layout="${machinename}" />
<parameter name="@logged" layout="${date}" />
<parameter name="@level" layout="${level}" />
<parameter name="@username" layout="${aspnet-user-identity}" />
<parameter name="@message" layout="${message}" />
<parameter name="@callsite" layout="${callsite}" />
<parameter name="@exception" layout="${exception:tostring}" />
</target>
</targets>
一个典型的文本文件和数据库的双写模式,但是很不幸的是 ${aspnet-user-identity} 是空的,比如我之前使用 Azure 的默认登录,${aspnet-user-identity} 是有值的,但是我改成了两个登录方案以后,${aspnet-user-identity} 就成空的了
app.UseEndpoints(endpoints =>
{
......
// Add endpoints for login challenges
endpoints.MapGet("/login-customer", async context =>
{
await context.ChallengeAsync(_customerAuthType, new AuthenticationProperties
{
RedirectUri = "/"
});
});
endpoints.MapGet("/login-support-agent", async context =>
{
await context.ChallengeAsync(_supportAgentAuthType, new AuthenticationProperties
{
RedirectUri = "/"
});
});
......
}
这个时候可以采用中间件的方式来解决,中间件的位置很重要,放在
app.UseAuthentication();
app.UseAuthorization();
之后,紧挨着
app.Use(async (context, next) =>
{
if (context.User.Identity.IsAuthenticated)
{
// Get the preferred username from claims
string userName = context.User.Claims.FirstOrDefault(obj => obj.Type == "preferred_username")?.Value;
// Set the user name in the NLog's MappedDiagnosticsLogicalContext
if (!string.IsNullOrEmpty(userName))
{
using (MappedDiagnosticsLogicalContext.SetScoped("userName", userName))
{
// Call the next middleware
await next();
}
}
else
{
// Preferred username is not found in claims
await next();
}
}
else
{
// User is not authenticated, do nothing
await next();
}
});
MappedDiagnosticsLogicalContext 就是NLog 的上下文方法,用法可自行查阅,然后把NLog 的配置文件的 ${aspnet-user-identity} 替换成 ${mdlc:userName},修改如下
<!-- the targets to write to -->
<targets async="true">
<target name="fileTarget" xsi:type="File" fileName="..\logs\${shortdate}.txt"
layout="${longdate} ${uppercase:${level}} ${mdlc:userName} ${aspnet-TraceIdentifier} ${callsite} ${message}"
archiveFileName="..\logs\${shortdate}.{#}.txt" archiveEvery="Day" archiveNumbering="Rolling"
maxArchiveFiles="60" concurrentWrites="true" keepFileOpen="false" />
<!--layout="${longdate} ${aspnet-user-identity} ${ndlc:bottomFrames=0:topFrames=1} ${aspnet-TraceIdentifier:ignoreActivityId=false} ${uppercase:${level}} ${logger} ${message}"-->
<target name="dbTarget"
xsi:type="Database"
dbProvider="sqlserver"
connectionString="${configsetting:name=ConnectionStrings.Default}"
keepConnection="true"
commandType="StoredProcedure"
commandText="[dbo].[usp_AddLog]">
<parameter name="@machineName" layout="${machinename}" />
<parameter name="@logged" layout="${date}" />
<parameter name="@level" layout="${level}" />
<parameter name="@username" layout="${mdlc:userName}" />
<parameter name="@message" layout="${message}" />
<parameter name="@callsite" layout="${callsite}" />
<parameter name="@exception" layout="${exception:tostring}" />
</target>
</targets>
数据插入成功