Asp.Net Core 2 oidc 中间件在代理请求后不挑战 returns 401

Asp.Net Core 2 oidc middleware does not challenge after proxy request returns 401

我正在尝试构建一个集中式代理,它将拦截所有请求并使用 openidconnect 处理身份验证。

目前代理的请求只是 returns 401,所以中间件应该挑战并将我重定向到登录页面。问题是使用 .Net Core 1.1 的实现它可以工作,但它似乎在 .Net Core 2 中不起作用。

我已经简化了代码,但是这有效,我被重定向到 google 的登录页面。

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddAuthentication();
        services.AddProxy();
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AutomaticAuthenticate = true,
        });

        app.UseGoogleAuthentication(new GoogleOptions
        {
            AutomaticChallenge = true,
            SignInScheme = "oidc",
            ClientId = "clientId",
            ClientSecret = "clientSecret",
        });

        app.MapWhen(
            context => context.RequestStartsWith("http://www.web1.com"),
            builder => builder.RunProxy(baseUri: new Uri("http://www.proxy1.com"))
        );
    }
}

这不适用于 .Net Core 2.0 的实现,我收到 401 异常页面

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddAuthentication(options =>
        {
            options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = GoogleDefaults.AuthenticationScheme;
        })
        .AddCookie()
        .AddGoogle(options =>
        {
            options.ClientId = "clientId";
            options.ClientSecret = "clientSecret";
        });

        services.AddProxy();
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseAuthentication();

        app.MapWhen(
            context => context.RequestStartsWith("http://www.web1.com"),
            builder => builder.RunProxy(baseUri: new Uri("http://www.proxy1.com"))
        );
    }
}

有什么想法吗?

查看源码发现Asp.NetCore 2中的Authentication中间件在响应returns 401状态码后并没有挑战,所以干脆returnHttpUnauthorizedResult 不再工作了。 Authorize 属性起作用的原因是它 return 是一个 ChallengeResult,它最终会调用 ChallengeAsync.

解决方法是,我创建了自己的中间件来处理 401 状态码

public class ChallengeMiddleware
{
    private readonly RequestDelegate _next;
    private readonly IAuthenticationSchemeProvider _schemes;

    public ChallengeMiddleware(RequestDelegate next, IAuthenticationSchemeProvider schemes)
    {
        _next = next;
        _schemes = schemes;
    }

    public async Task Invoke(HttpContext context)
    {
        context.Response.OnStarting(async () =>
        {
            if (context.Response.StatusCode == 401)
            {
                var defaultChallenge = await _schemes.GetDefaultChallengeSchemeAsync();
                if (defaultChallenge != null)
                {
                    await context.ChallengeAsync(defaultChallenge.Name);
                }
            }
            await Task.CompletedTask;
        });

        await _next(context);
    }
}