我们最终得到的解决方案相当笨拙,但只要您使用 Cookie auth 中间件,它就可以工作:
services.ConfigureApplicationCookie(options =>
{
options.Events = new CookieAuthenticationEvents
{
OnRedirectToAccessDenied = async ctx =>
{
ctx.Response.StatusCode = 401;
ctx.Response.ContentType = "text/html";
var service = ctx.HttpContext.RequestServices.GetService(typeof(IViewRenderService)) as IViewRenderService;
await ctx.Response.WriteAsync(await service.RenderToStringAsync("Errors/Unauthorized", null), Encoding.ASCII);
}
};
});
ViewRenderService 是这样的(可以在其他地方找到几个示例):
public class ViewRenderService : IViewRenderService
{
private readonly IRazorViewEngine _razorViewEngine;
private readonly ITempDataProvider _tempDataProvider;
private readonly IServiceProvider _serviceProvider;
private readonly HttpContext _httpContext;
public ViewRenderService(IRazorViewEngine razorViewEngine,
ITempDataProvider tempDataProvider,
IServiceProvider serviceProvider,
IHttpContextAccessor httpContextAccessor)
{
_razorViewEngine = razorViewEngine;
_tempDataProvider = tempDataProvider;
_serviceProvider = serviceProvider;
_httpContext = httpContextAccessor.HttpContext;
}
public async Task<string> RenderToStringAsync(string viewName, object model)
{
var actionContext = new ActionContext(_httpContext, _httpContext.GetRouteData(), new ActionDescriptor());
using var sw = new StringWriter();
var viewResult = _razorViewEngine.FindView(actionContext, viewName, true);
if (viewResult.View == null)
{
throw new ArgumentNullException($"{viewName} does not match any available view");
}
var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
{
Model = model
};
var viewContext = new ViewContext(
actionContext,
viewResult.View,
viewDictionary,
new TempDataDictionary(_httpContext, _tempDataProvider),
sw,
new HtmlHelperOptions()
);
await viewResult.View.RenderAsync(viewContext);
return sw.ToString();
}
}