Aspnetcore Bearer auth:在中间件内部使用用户

时间:2018-12-30 22:21:48

标签: asp.net-core oauth middleware

我在应用程序中使用Cookie和承载身份验证。但是我有一种奇怪的行为,我无法解释。

我确实有自定义的中间件,在其中我向Context.Items添加了一些必需的数据。这一切都很好,但在该中间件中,如果用户的承载是空的,则它的cookie是正确的。

   services
                .AddAuthorization(options =>
                {
                    options.DefaultPolicy = new AuthorizationPolicyBuilder()
                        .AddAuthenticationSchemes(OAuthValidationDefaults.AuthenticationScheme,
                            CookieAuthenticationDefaults.AuthenticationScheme,
                            "Identity.Application")
                        .RequireAuthenticatedUser()
                        .Build();
                });
            //CookieAuthenticationDefaults.AuthenticationScheme
            services.AddAuthentication()
                .AddExternalAuthProviders(Configuration)
                .AddFlymarkOpenIdConnectServer()
                .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
                {
                    options.LoginPath = "/Identity/Account/LogIn";
                    options.SlidingExpiration = true;
                    options.Events.OnRedirectToLogin = OnRedirectToLogin;
                })
                .AddOAuthValidation(OAuthValidationDefaults.AuthenticationScheme,
                    o=>o.Events.OnCreateTicket = OnCreateTicket);
            services.ConfigureApplicationCookie(config =>
            {
                config.Events = new CookieAuthenticationEvents
                {
                    OnRedirectToLogin = OnRedirectToLogin
                };
            });

我在CreateTicket上使用的临时解决了我的问题

   private async Task OnCreateTicket(CreateTicketContext arg)
        {
            if (arg.HttpContext.Items[FlymarkWeb.CurrentUserKey] == null && arg.Identity.IsAuthenticated)
            {
                var db= (FlymarkContext) arg.HttpContext.RequestServices.GetService(typeof(FlymarkContext));
                arg.HttpContext.Items[FlymarkWeb.CurrentUserKey] =
                    await db.Users.FirstOrDefaultAsync(u => u.Id == arg.Identity.GetUserId());
            }
        }

和中间件

  public async Task Invoke(HttpContext httpContext, FlymarkContext context, DomainService _sourceDomainService)
        {
            if (httpContext.Items[FlymarkWeb.CurrentUserKey] == null)
            {
                httpContext.Items[FlymarkWeb.CurrentUserKey] = httpContext.User.Identity.IsAuthenticated
                    ? await context.Users.FirstOrDefaultAsync(u => u.Id == httpContext.User.GetUserId())
                    : null;
            }
....
}

所以我的问题是为什么cookie和oauth不同?为什么如果我的cookie可以访问中间件中的用户,而我的oauth无法访问?

1 个答案:

答案 0 :(得分:1)

那是因为调用services.AddIdentity()时ASP.NET Core身份registers itself as the default authentication scheme handler

app.UseAuthentication()后面的中间件收到请求后,将自动调用Identity注册的cookie身份验证处理程序,并使用从身份验证cookie中提取的结果HttpContext.User填充ClaimsPrincipal

使用不记名令牌,这不会发生,因为OAuth验证处理程序不会将自身注册为默认的身份验证处理程序(这是您必须在2.0版中手动明确进行的操作)。

要将其配置为默认处理程序,您可以执行以下操作:

services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = OAuthValidationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OAuthValidationDefaults.AuthenticationScheme;
});

或者,您可以直接自己执行身份验证操作,而不必依赖HttpContext.User。例如:

public async Task Invoke(HttpContext httpContext, FlymarkContext context, DomainService _sourceDomainService)
{
    if (httpContext.Items[FlymarkWeb.CurrentUserKey] == null)
    {
        var principal = (await httpContext.AuthenticateAsync(OAuthValidationDefaults.AuthenticationScheme))?.Principal;

        httpContext.Items[FlymarkWeb.CurrentUserKey] = principal?.Identity != null && principal.Identity.IsAuthenticated
            ? await context.Users.FirstOrDefaultAsync(u => u.Id == principal.GetUserId())
            : null;
    }
}