【发布时间】:2018-02-26 16:52:40
【问题描述】:
我正在尝试向 Serilog 提供 ActiveUser 属性。
不幸的是,我似乎找不到正确的位置来检查当前用户。
在下面的代码中httpContext.User.Identity.IsAuthenticated总是false?
但仅在使用不记名令牌登录时
- 不记名令牌登录工作正常,只要用户是 验证到控制器方法,并且用户需要属于 到正确的角色以便进行身份验证。虽然用户名设置不正确 - 声明存在,并且 IsAuthenticated 设置为 true。
- 如果我使用cookie登录,用户设置正确,声明设置正确,Serilog工作正常。无论是使用不记名令牌还是使用 cookie 来调用都是如此。一旦用户使用 cookie 登录,它就始终有效。
当承载令牌被验证时,用户不是立即设置的吗?
项目是aspnetcore 2.0
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
... (other configuration items)
app.UseIdentityServer();
app.UseAuthentication();
app.Use(async (httpContext, next) =>
{
// HERE IsAuthenticated IS ALWAYS FALSE
// HERE THE CLAIMS ARE ALWAYS EMPTY, UNLESS
// I LOGIN USING THE COOKIE AS WELL - THEN IT WORKS
var userName = httpContext.User.Identity.IsAuthenticated
? httpContext.User.GetClaim("name")
: "(unknown)";
LogContext.PushProperty(
"ActiveUser",
!string.IsNullOrWhiteSpace(userName)
? userName
: "(unknown)");
await next.Invoke();
});
app.UseMvc(
routes =>
{
routes.MapRoute(
"default",
"{controller=Home}/{action=Index}/{id?}");
});
在我的控制器方法中,用户设置正确,并且经过身份验证。
[Authorize]
[HttpGet("user")]
public object UserDetail()
{
// HERE THE CLAIMS ARE SET, IsAuthenticated IS ALWAYS TRUE
// AS THE USER MUST BE AUTHENTICATED TO GET HERE
Debug.Assert(this.User.Identity.IsAuthenticated == true)
编辑
进一步深入研究这个问题,JWTBearer 令牌似乎是在我的中间件已经执行之后得到验证的。中间件需要在验证令牌后执行。
TL;DR
(完整配置)
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseIdentityServer();
app.UseAuthentication();
app.Use(async (httpContext, next) =>
{
var userName = httpContext.User.Identity.IsAuthenticated
? httpContext.User.GetClaim("email")
: "(unknown)";
LogContext.PushProperty("ActiveUser", !string.IsNullOrWhiteSpace(userName) ? userName : "(unknown)");
await next.Invoke();
});
app.UseMvc(
routes =>
{
routes.MapRoute(
"default",
"{controller=Home}/{action=Index}/{id?}");
});
}
(更多配置)
public void ConfigureServices(IServiceCollection services)
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.AddAuthentication()
.AddOpenIdConnect(
o =>
{
o.Authority = "https://localhost:44319";
o.ClientId = "api";
o.ClientSecret = "secret";
o.RequireHttpsMetadata = false;
o.ResponseType = "code id_token token";
o.GetClaimsFromUserInfoEndpoint = true;
})
.AddJwtBearer(
o =>
{
o.Authority = "https://localhost:44319";
o.Audience = "api";
o.RequireHttpsMetadata = false;
//o.SaveToken = true;
});
services.AddMemoryCache();
services.AddIdentity<ApplicationUser, ApplicationRole>(
x =>
{
x.Password.RequireNonAlphanumeric = false;
x.Password.RequireUppercase = false;
})
.AddEntityFrameworkStores<FormWorkxContext>()
.AddDefaultTokenProviders()
.AddIdentityServer();
// NB
services.Configure<IdentityOptions>(
options =>
{
options.ClaimsIdentity.RoleClaimType = ClaimTypes.Role;
options.ClaimsIdentity.UserNameClaimType = ClaimTypes.Name;
});
services.ConfigureApplicationCookie(
options =>
{
options.LoginPath = "/login";
options.LogoutPath = "/logout";
options.Events.OnRedirectToLogin = this.ProcessStatusCodeResponse;
});
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(Config.GetApis())
.AddInMemoryClients(Config.GetClients())
.AddAspNetIdentity<ApplicationUser>();
services.AddTransient<IEmailSender, EmailSender>();
services.AddMvc(
_ =>
{
_.Filters.Add(
new AuthorizeFilter(
new AuthorizationPolicyBuilder(
JwtBearerDefaults.AuthenticationScheme,
IdentityConstants.ApplicationScheme)
.RequireAuthenticatedUser()
.Build()));
_.Filters.Add(new ExceptionFilter());
_.ModelBinderProviders.Insert(0, new PartyModelBinderProvider());
_.ModelBinderProviders.Insert(0, new DbGeographyModelBinder());
_.ModelMetadataDetailsProviders.Add(new KeyTypeModelMetadataProvider());
})
.AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining<Startup>())
.AddJsonOptions(json => json.SerializerSettings.Converters.Add(new DbGeographyJsonConverter()));
}
【问题讨论】:
-
显示配置服务方法。
-
当您说“用户设置正确”时,您的意思是 Identity.Name 对吗?如果是,我遇到了同样的问题,它向我显示了名称,但没有将 IsAuthenticated 设置为 true。当我更改我的登录代码时,它会将登录设置为 true。您究竟是如何登录用户的。
-
您的 Configure 方法仅在应用启动时运行一次,此时没有用户甚至 http 上下文。我还没有使用 Serilog(还),但在实际记录某些内容时,您可能需要将用户作为数据的一部分。 LogContext 听起来它也是一个单例,与特定用户会话无关。
-
@Neville,抱歉,我应该具体一点,未设置任何声明,未设置用户。用户根本不存在。稍后在管道中(在实际的控制器方法中)它都设置正确。不幸的是,登录很复杂 - 使用 JWTToken 和身份服务器。我可以发布完整的配置 - 我只是想尽可能简短。
-
@rory_za,add 方法采用一个 lambda,该 lambda 在管道上为每个请求重新执行。所以是的,当第一次传入 lambda 时,没有上下文,但 lambda 接收当前上下文和序列中的下一个处理程序。
标签: c# asp.net-mvc identityserver4 serilog asp.net-core-middleware