抑制ASP.NET Core中API URL的重定向

22
我有一个使用cookie身份验证的ASP.NET Core网站,大部分页面都是这样。对于那些页面,服务器默认响应为向未经授权的客户端提供302重定向是理想的。但是,该网站还接受API请求;它们使用API密钥,不需要cookie。
理想情况下,我希望完全关闭API URL的cookie处理,但至少需要确保如果API客户端未经授权,则服务器不会响应302重定向。
3个回答

45

如果路径不是API,则将重定向事件处理程序替换为仅使用默认行为。在Startup.ConfigureServices中添加以下内容:

services.ConfigureApplicationCookie(options => {
    options.Events.OnRedirectToAccessDenied = ReplaceRedirector(HttpStatusCode.Forbidden, options.Events.OnRedirectToAccessDenied);
    options.Events.OnRedirectToLogin = ReplaceRedirector(HttpStatusCode.Unauthorized, options.Events.OnRedirectToLogin);
});

使用此辅助方法来替换重定向方法:

static Func<RedirectContext<CookieAuthenticationOptions>, Task> ReplaceRedirector(HttpStatusCode statusCode, Func<RedirectContext<CookieAuthenticationOptions>, Task> existingRedirector) =>
    context => {
        if (context.Request.Path.StartsWithSegments("/api")) {
            context.Response.StatusCode = (int)statusCode;
            return Task.CompletedTask;
        }
        return existingRedirector(context);
    };

通过这样处理,API控制器方法可以调用Unauthorized()Forbid()而不会导致重定向。

更新:上述内容适用于ASP.NET Core 2。ASP.NET Core 1的代码有所不同。


3
+1. 需要注意的是,在设置身份验证(在我的情况下是 services.AddIdentity())之后,应该调用 services.ConfigureApplicationCookie(),否则这些设置将被覆盖。 - Sabre
当与spa一起使用时,这似乎是一种非常干净的方式。 - liang
2
我尝试在我的.NET Core 3.0 Web API项目中实现您的解决方案,但没有成功。似乎传递给ConfigureApplicationCookie的操作委托参数从未被调用;我在其第一行上设置了断点,但它从未被触发。当我的测试API控制器调用Forbid时,我的测试客户端应用程序仍然收到HTTP状态码500而不是403。有什么想法吗? - Bart Hofland
这里在使用 .NET Core 3.1 时遇到了同样的问题。这段代码似乎根本不起作用。有什么想法吗? - killswitch
1
这是一个非常出色的解决方案,我可以确认它可以在.NET Core 5.0中运行。 - Lavamantis

5

针对 .net core 2.x,以下是一种修复方法(基于 Edward 的答案):

services.ConfigureApplicationCookie(options =>
        {
            options.Events = new CookieAuthenticationEvents
            {
                OnRedirectToAccessDenied = ReplaceRedirector(HttpStatusCode.Forbidden, context => options.Events.RedirectToAccessDenied(context)),
                OnRedirectToLogin = ReplaceRedirector(HttpStatusCode.Unauthorized, context => options.Events.RedirectToLogin(context))
            };
        });

其中ReplaceRedirector

Func<RedirectContext<CookieAuthenticationOptions>, Task> ReplaceRedirector(HttpStatusCode statusCode, Func<RedirectContext<CookieAuthenticationOptions>, Task> existingRedirector) =>
context =>
{
    if (context.Request.Path.StartsWithSegments("/api"))
    {
        context.Response.StatusCode = (int)statusCode;
        return Task.CompletedTask;
    }
    return existingRedirector(context);
};

1
我更新了我的答案并包括了ASP.NET Core 2。在我的更新中,我没有替换“Events”,而是只设置了其相关属性。 - Edward Brey

2
最初的回答

其他简单方法

 .AddCookie(options =>
            {
                options.AccessDeniedPath = "/Home/401";
                options.Events = new CookieAuthenticationEvents
                {
                    OnRedirectToAccessDenied = context => 
                    {
                        if (context.Request.Path.StartsWithSegments("/api"))
                        {
                            context.Response.StatusCode = (int)(HttpStatusCode.Unauthorized);
                        }
                        return Task.CompletedTask;
                    },
                };
            })

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接