我创建一个多租户网站,其中包含了客户端的网页。 URL的第一区段将是一个字符串,它识别客户端,使用下面的URL路由方案在Global.asax中定义:

"{client}/{controller}/{action}/{id}"

这个工作得很好,有URL如/富/主页/索引。

然而,使用[授权]属性时,我要重定向到也使用相同的映射方案的登录页面。因此,如果客户机是foo,登录页面将是/富/帐户/登录而不是在web.config中定义的固定/帐户/登录重定向。

MVC使用一个HttpUnauthorizedResult返回一个未经授权的401种状态,这是我假定使ASP.NET重定向到web.config中定义的页面。

因此,没有人知道或者如何重写ASP.NET登录重定向行为?还是会更好通过创建自定义的授权属性在MVC重定向?

修改 - 答案:一些挖掘到.NET源后,我决定定制认证属性是最佳的解决方案:

public class ClientAuthorizeAttribute: AuthorizeAttribute
{
    public override void OnAuthorization( AuthorizationContext filterContext )
    {
        base.OnAuthorization( filterContext );

        if (filterContext.Cancel && filterContext.Result is HttpUnauthorizedResult )
        {
            filterContext.Result = new RedirectToRouteResult(
                new RouteValueDictionary
                {
                    { "client", filterContext.RouteData.Values[ "client" ] },
                    { "controller", "Account" },
                    { "action", "Login" },
                    { "ReturnUrl", filterContext.HttpContext.Request.RawUrl }
                });
        }
    }
}
有帮助吗?

解决方案

我认为主要的问题是,如果你要捎带上内置的ASP.NET FormsAuthentication类(有你不应该没有充分的理由),一些在这一天结束时要调用这是会看一个配置的URL FormsAuthentication.RedirectToLoginPage()。这里只有一个登录网址,永远,那就是他们是如何设计的。

我在这个问题(可能是出自临时抱佛脚实现)刺会让它重定向到一个登录页面,在所有客户端共享的根,说/帐号/登录。这个登录页面实际上不会显示任何画面;它会检查无论是RETURNURL参数或一定的价值,我在会议上得到或可识别客户端,并使用该发出即时302重定向到具体/客户/帐号/登录页面的cookie。这是一个额外的重定向,但可能并不明显,它可以让你使用内置的重定向机制。

另一种选择是你描述和避免任何呼吁RedirectToLoginPage()FormsAuthentication方法,因为你会用自己的重定向逻辑来取代它来创建自己的自定义属性。 (您可以创建自己的类类似。)由于它是一个静态类,我不知道的,你可能只是注入自己的替代接口的任何机制,并奇迹般地与现有的[授权]属性,工作当中打击,但之前做过类似的事情。

希望帮助!

其他提示

在ASP.NET MVC的RTM版本,Cancel属性丢失。该代码可以使用ASP.NET MVC RTM:

using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Resources;

namespace ePegasus.Web.ActionFilters
{
    public class CustomAuthorize : AuthorizeAttribute
    {
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            base.OnAuthorization(filterContext);
            if (filterContext.Result is HttpUnauthorizedResult)
            {
                filterContext.Result = new RedirectToRouteResult(
                    new System.Web.Routing.RouteValueDictionary
                        {
                                { "langCode", filterContext.RouteData.Values[ "langCode" ] },
                                { "controller", "Account" },
                                { "action", "Login" },
                                { "ReturnUrl", filterContext.HttpContext.Request.RawUrl }
                        });
            }
        }
    }
}

编辑:您可能要禁用web.config中的默认窗体身份验证loginUrl - 万一有人忘记你有一个自定义属性,并使用内置的错误[授权]属性

在web.config中

修改值:

 <forms loginUrl="~/Account/ERROR" timeout="2880" />

然后制定行动方法“错误”是记录错误,并将用户重定向到您拥有最通用的登录页面。

我的对这个问题的解决方案是自定义ActionResult类:

    sealed public class RequiresLoginResult : ActionResult
    {
        override public void ExecuteResult (ControllerContext context)
        {
            var response = context.HttpContext.Response;

            var url = FormsAuthentication.LoginUrl;
            if (!string.IsNullOrWhiteSpace (url))
                url += "?returnUrl=" + HttpUtility.UrlEncode (ReturnUrl);

            response.Clear ();
            response.StatusCode = 302;
            response.RedirectLocation = url;
        }

        public RequiresLoginResult (string returnUrl = null)
        {
            ReturnUrl = returnUrl;
        }

        string ReturnUrl { get; set; }
    }

不过,如果一个决定使用内置的ASP.NET FormsAuthentication,人们可以在Application_AuthenticateRequest此改变Global.asax.cs如下:

protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
    string url = Request.RawUrl;

    if (url.Contains(("Account/Login"))
    {
        return;
    }

    if (Context.User == null)
    {
        // Your custom tenant-aware logic
        if (url.StartsWith("/foo"))
        {
            // Your custom login page.
            Response.Redirect("/foo/Account/Login");
            Response.End();
            return;
        }
    }
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top