首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >aspnet-5 mvc-6中的自定义授权IActionResults

aspnet-5 mvc-6中的自定义授权IActionResults
EN

Stack Overflow用户
提问于 2015-12-19 20:30:05
回答 2查看 2.5K关注 0票数 1

在ASP.NET 4 MVC5中,这个类允许我向JSON端点返回未经身份验证的响应的自定义响应。这就是了。

代码语言:javascript
运行
复制
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (IsAjax(filterContext))
        {
            filterContext.Result = new JsonResult
            {
                JsonRequestBehavior = JsonRequestBehavior.AllowGet,
                Data = new
                {
                    success = false,
                    error = "You must be signed in."
                }
            };
        }
        else
        {
            base.HandleUnauthorizedRequest(filterContext);
        }
    }

    private bool IsAjax(AuthorizationContext filterContext)
    {
        return filterContext.ActionDescriptor.GetFilterAttributes(true).OfType<AjaxAttribute>().FirstOrDefault() !=
                null;
    }
}

但是,在MVC6中,新的AuthorizeAttribute并不是用于创建自定义IActionResult结果的重写。我如何在MVC6中做到这一点?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-12-21 10:52:54

我看了消息来源后终于弄明白了。

代码语言:javascript
运行
复制
public class CustomCookieAuthenticationEvents : CookieAuthenticationEvents
{
    Func<CookieRedirectContext, Task> _old;
    public CustomCookieAuthenticationEvents()
    {
        _old = OnRedirectToLogin;
        OnRedirectToLogin = OnCustomRedirectToLogin;
    }

    public Task OnCustomRedirectToLogin(CookieRedirectContext context)
    {
        var actionContext = context.HttpContext.RequestServices.GetRequiredService<IActionContextAccessor>();
        if (actionContext.ActionContext == null)
            return _old(context);

        if (actionContext.ActionContext.ActionDescriptor.FilterDescriptors.Any(x => x.Filter is AjaxAttribute))
        {
            // this is an ajax request, return custom JSON telling user that they must be authenticated.
            var serializerSettings = context
                .HttpContext
                .RequestServices
                .GetRequiredService<IOptions<MvcJsonOptions>>()
                .Value
                .SerializerSettings;

            context.Response.ContentType = "application/json";

            using (var writer = new HttpResponseStreamWriter(context.Response.Body, Encoding.UTF8))
            {
                using (var jsonWriter = new JsonTextWriter(writer))
                {
                    jsonWriter.CloseOutput = false;
                    var jsonSerializer = JsonSerializer.Create(serializerSettings);
                    jsonSerializer.Serialize(jsonWriter, new
                    {
                        success = false,
                        error = "You must be signed in."
                    });
                }
            }

            return Task.FromResult(0);
        }
        else
        {
            // this is a normal request to an endpoint that is secured.
            // do what ASP.NET used to do.
            return _old(context);
        }
    }
}

然后,按以下方式使用此事件类:

代码语言:javascript
运行
复制
services.Configure<IdentityOptions>(options =>
{
    options.Cookies.ApplicationCookie.Events = new CustomCookieAuthenticationEvents();
});

ASP.NET 5确实使简单的事情更难做。当然,我现在可以在更细粒度的级别上定制事物,而不会影响其他部分。而且,源代码非常容易阅读/理解。我很高兴有这样的信心,我所拥有的任何问题都可以很容易地被识别为bug,或者通过查看源代码来解决。

为未来干杯!

票数 0
EN

Stack Overflow用户

发布于 2015-12-21 13:28:28

his comment中的@blowdart提出了一个很好的观点,即返回401/403是否应该是预期的行为。无论如何,我尝试了一种不同的方法来执行OP要求的操作,修改默认MVC授权过滤器的行为,以便在用户未经授权时返回json。

我做的第一件事是创建一个新的IAsyncAuthorizationFilter,将未经授权的结果格式化为用于ajax请求的json。它将基本上:

  1. 包装现有的过滤器
  2. 执行包装过滤器
  3. 如果用户被包装过滤器未经授权,请为ajax请求返回json。

这将是CustomJsonAuthorizationFilter类:

代码语言:javascript
运行
复制
public class CustomJsonAuthorizationFilter : IAsyncAuthorizationFilter
{
    private AuthorizeFilter wrappedFilter;
    public CustomJsonAuthorizationFilter(AuthorizeFilter wrappedFilter)
    {
        this.wrappedFilter = wrappedFilter;
    }

    public async Task OnAuthorizationAsync(Microsoft.AspNet.Mvc.Filters.AuthorizationContext context)
    {
        await this.wrappedFilter.OnAuthorizationAsync(context);
        if(context.Result != null && IsAjaxRequest(context))
        {
            context.Result = new JsonResult(new
            {
                success = false,
                error = "You must be signed in."
            });
        }
        return;
    }

    //This could be an extension method of the HttpContext/HttpRequest
    private bool IsAjaxRequest(Microsoft.AspNet.Mvc.Filters.AuthorizationContext filterContext)
    {
        return filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest";
    }
}

然后,我创建了一个IApplicationModelProvider,以便用新的自定义过滤器包装所有现有的AuthorizeFilterAuthroizeFilterAuthorizationApplicationModelProvider添加,但是新提供程序将在默认提供程序之后运行,因为默认提供程序的顺序是-990。

代码语言:javascript
运行
复制
public class CustomFilterApplicationModelProvider : IApplicationModelProvider
{
    public int Order
    {
        get { return 0; }
    }

    public void OnProvidersExecuted(ApplicationModelProviderContext context)
    {
        //Do nothing
    }

    public void OnProvidersExecuting(ApplicationModelProviderContext context)
    {
        this.ReplaceFilters(context.Result.Filters);
        foreach(var controller in context.Result.Controllers)
        {
            this.ReplaceFilters(controller.Filters);
            foreach (var action in controller.Actions)
            {
                this.ReplaceFilters(action.Filters);
            }
        }
    }

    private void ReplaceFilters(IList<IFilterMetadata> filters)
    {
        var authorizationFilters = filters.OfType<AuthorizeFilter>().ToList();
        foreach (var filter in authorizationFilters)
        {
            filters.Remove(filter);
            filters.Add(new CustomJsonAuthorizationFilter(filter));
        }
    }
}

最后,使用新的应用程序模型提供程序在启动时更新ConfigureServices

代码语言:javascript
运行
复制
services.TryAddEnumerable(
            ServiceDescriptor.Transient<IApplicationModelProvider, CustomFilterApplicationModelProvider>());
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34375083

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档