我正在尝试向Serilog提供ActiveUser
财产
不幸的是,我似乎无法找到检查当前用户的正确位置。
在下面的代码中,httpContext.User.Identity.IsAuthenticated
总是 false?
但仅在使用持有人令牌登录
时当验证承载令牌时,用户不会立即设置?
该项目是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()));
}
答案 0 :(得分:2)
复制my answer from your other related question以防万一有人遇到这个并想知道发生了什么:
由于您注册了多个身份验证方案,因此没有注册 默认情况下,身份验证不会自动发生 请求通过管道。这就是
HttpContext.User
的原因 当它通过您的自定义中间件时,它是空的/未经身份验证的。 在这种“被动”模式下,不会调用认证方案 直到它被要求。在您的示例中,这发生在请求时 通过你的AuthorizeFilter
。这会触发JWT 身份验证处理程序,用于验证令牌,验证和 设置标识等。这就是正确填充User
的原因 当它到达你的控制器动作时。
答案 1 :(得分:0)
我使用如下设置的主体登录时复制了此问题:
var principal = new ClaimsPrincipal(new ClaimsIdentity(claims));
然后我使用SignInAsync
登录。这也导致User.Identity.Name
具有值,但User.Identity.IsAuthenticated
未设置为true。
现在,当我将authenticationType
参数添加到ClaimsIdentity
时,就像这样:
var principal = new ClaimsPrincipal(new ClaimsIdentity(claims, "local"));
IsAuthenticated
现在设置为true。
我不完全确定您的登录方式是如何工作的,您可以在某处提及此authenticationType
,或者您可以在创建JWT时将其传递出去。这就是我做的方式。
更新确定只是注意到您对未显示的名称的评论,但您仍然可以尝试设置authenticationType。此外,就您的主张是正确的,您应该能够使用AuthenticateAsync
提取原则。一旦您可以从Context.User
对象访问原则,您始终可以自定义强制在主体中的身份验证方案。
更新2 在您的情况下,在AddJwtBearer
内,请尝试将其包括在内:
o.Events.OnTokenValidated = async (context) => {
context.Principal = new ClaimsPrincipal(new ClaimsIdentity(context.Principal.Claims, "local"));
};
答案 2 :(得分:0)
通过添加以下代码行,在自定义中间件中对用户进行显式身份验证:
var result = await context.Request.HttpContext.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);//AuthenticationOptions.DefaultAuthenticateScheme)
if (result.Succeeded)
{
//context.User.AddIdentity(result.Principal);
context.User = result.Principal;
}