c# - ASP。带有 cookie 身份验证的 Net Core 2.2:当未授权仅 API 控制器时如何避免页面重定向
问题描述
我的 ASP .Net Core 2.2 Web 应用程序有一些返回View
(s) 的控制器和一些返回 json 结果的控制器,因为它们只是API控制器。
我的网站使用cookie authentication,声明如下:
services
.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.AccessDeniedPath = "/Pages/AccessDenied";
options.Cookie.HttpOnly = true;
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.Cookie.SameSite = SameSiteMode.Strict;
});
在该Configuration
部分:
// ...
app.UseAuthentication();
app.UseDefaultFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Pages}/{action=Index}/{id?}");
});
我PagesController
只是继承自某些页面,Microsoft.AspNetCore.Mvc.Controller
并为某些页面设置了[Authorize]
属性。当非授权用户尝试打开该页面时,它会被正确重定向到我的公共AccessDenied
页面。一切都很好。
但是,我也有一个ApiController
,它继承自Microsoft.AspNetCore.Mvc.ControllerBase
,有一个属性[ApiController]
,还有一个[Authorize(Roles = "Administrator")]
. 我使用此控制器与页面中的 javascript 进行通信。问题是,当非授权用户尝试调用此控制器上的方法时,我不希望它响应 HTTP 200 页面(那个AccessDenied
),但我希望它只返回 HTTP 401 Unauthorized 因为它是一个 API。
我怎样才能实现这种不同的行为来保持 cookie 身份验证?
谢谢!
解决方案
获得此行为的最简单方法是编写一个派生自CookieAuthenticationEvents并覆盖RedirectToLogin和RedirectToAccessDenied的自定义类。
如果你不熟悉这个CookieAuthenticationEvents
类,你可以从文档中的这个例子开始。基本上,它是为 cookie 身份验证添加自定义行为的插件点。
首先,您需要一种方法来识别您的 AJAX 请求。最简单的方法是在所有 AJAX 请求的请求路径中使用公共前缀。例如,您可以决定所有 AJAX 请求路径都以/api
.
您可以编写以下自定义CookieAuthenticationEvents
类:
public sealed class CustomCookieAuthenticationEvents : CookieAuthenticationEvents
{
public override Task RedirectToAccessDenied(
RedirectContext<CookieAuthenticationOptions> context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
if (IsAjaxRequest(context.HttpContext))
{
context.Response.StatusCode = StatusCodes.Status403Forbidden;
return Task.CompletedTask;
}
else
{
// non AJAX requests behave as usual
return base.RedirectToAccessDenied(context);
}
}
public override Task RedirectToLogin(RedirectContext<CookieAuthenticationOptions> context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
if (IsAjaxRequest(context.HttpContext))
{
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
return Task.CompletedTask;
}
else
{
// non AJAX requests behave as usual
return base.RedirectToLogin(context);
}
}
private static bool IsAjaxRequest(HttpContext httpContext)
{
var requestPath = httpContext.Request.Path;
return requestPath.StartsWithSegments(new PathString("/api"), StringComparison.OrdinalIgnoreCase);
}
}
现在您可以CookieAuthenticationEvents
在您的方法中使用身份验证服务注册您的自定义Startup.ConfigureServices
:
services
.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.AccessDeniedPath = "/Pages/AccessDenied";
options.Cookie.HttpOnly = true;
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.Cookie.SameSite = SameSiteMode.Strict;
options.EventsType = typeof(CustomCookieAuthenticationEvents);
});
services.AddSingleton<CustomCookieAuthenticationEvents>();
推荐阅读
- ios - 如何使用 SwiftUI 观察 TextField 值并结合?
- java - 我正在尝试在 java 中合并两个 JsonObjects
- javascript - 刷新页面后的粗体活动菜单
- docker - 配置文件更改为 VerneMQ docker 映像
- spring - 为什么 Querydsl 总是要求连接是事务性的?
- android - 使用 Android 9(API 级别 28)连接到 wifi 网络
- laravel-5 - 在 fieldname=>fieldvalue 键中雄辩地获取数据
- c# - 如何在不影响行为的情况下处理表单中的 wndproc calcsize 进程进行自定义
- postgresql - postgres 10.1和hibernate的关系不存在错误
- c# - 无法从 OracleRefCursor 填充 DataTable