使用AuthorizeAttribute而不会在失败时触发URL重定向吗?

问题描述 投票:0回答:2

当前在ASP.NET Core MVC中,当使用ConfigureApplicationCookie和Authorize属性时,任何故障都将导致重定向到AccessDenied路径。

这给错误报告带来了挑战,因为最终用户无法看到最初请求的URL。这也使故障排除更加困难,因为页面刷新只会导致重新加载访问被拒绝的页面(而不会尝试重新授权。)

是否可以将中间件配置为无需重定向即可返回拒绝访问的状态代码页,类似于UseStatusCodePagesWithReExecute?

asp.net-mvc asp.net-core
2个回答
0
投票
    public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
    returnUrl = returnUrl ?? Url.Content("~/");

    if (ModelState.IsValid)
    {
        // This doesn't count login failures towards account lockout
        // To enable password failures to trigger account lockout, 
        // set lockoutOnFailure: true
        var result = await _signInManager.PasswordSignInAsync(Input.Email,
                           Input.Password, Input.RememberMe, lockoutOnFailure: true);
        if (result.Succeeded)
        {
            _logger.LogInformation("User logged in.");
            return LocalRedirect(returnUrl);
        }
    /* set if here if log in is not successful*/
    if (!result.Succeeded)
    {
       logger.log("stupid hacker");
    }
       if (result.RequiresTwoFactor)
        {
            return RedirectToPage("./LoginWith2fa", new
            {
                ReturnUrl = returnUrl,
                RememberMe = Input.RememberMe
            });
        }
        if (result.IsLockedOut)
        {
            _logger.LogWarning("User account locked out.");
            return RedirectToPage("./Lockout");
        }
        else
        {
            ModelState.AddModelError(string.Empty, "Invalid login attempt.");
            return Page();
        }
    }

    // If we got this far, something failed, redisplay form
    return Page();
}
as you can see in the lines when if method is fired and correct it redirect user to another page so what you want is redirect to current page that has already called authorization there you will get stackoverflow (wahahaha) there doing that will be wrong right? so what you do is put logger system in the if before redirect and you have every want to log and then redirect  

0
投票

我们最终得到的解决方案相当笨拙,但是只要您使用Cookie身份验证中间件,它就可以工作:

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();
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.