首页 文章

如何重定向到ASP.NET MVC中的动态登录URL

提问于
浏览
91

我正在创建一个多租户网站,为客户端托管页面 . URL的第一部分将是一个字符串,用于标识客户端,使用以下URL路由方案在Global.asax中定义:

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

这样工作正常,使用/ foo / Home / Index等URL .

但是,当使用[Authorize]属性时,我想重定向到也使用相同映射方案的登录页面 . 因此,如果客户端是foo,则登录页面将是/ foo / Account / Login,而不是web.config中定义的固定/帐户/登录重定向 .

MVC使用HttpUnauthorizedResult返回401未授权状态,我认为这会导致ASP.NET重定向到web.config中定义的页面 .

那么有谁知道如何覆盖ASP.NET登录重定向行为?或者通过创建自定义授权属性来重定向MVC会更好吗?

EDIT - Answer: 在深入研究.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 }
                });
        }
    }
}

3 回答

  • 40

    我认为主要的问题是,如果你没有理由你不应该这样做,那么在一天结束时会发生一些事情,即调用 FormsAuthentication.RedirectToLoginPage() ,它将查看一个配置的URL . 那里有's only one login URL, ever, and that'只是他们如何设计它 .

    我对这个问题的猜测(可能是Rube Goldberg的实现)是让它重定向到所有客户共享的根目录下的单个登录页面,比如/ account / login . 此登录页面实际上不会显示任何内容;它检查ReturnUrl参数或我在会话中获得的某个值,或检查标识客户端的cookie,并使用它来发出立即302重定向到特定/客户端/帐户/登录页面 . 这是一个额外的重定向,但可能不会引人注意,它允许您使用内置的重定向机制 .

    另一个选择是在你描述的时候创建你自己的自定义属性,并避免在 FormsAuthentication 类上调用 RedirectToLoginPage() 方法的任何东西,因为你是静态类,我不知道你可以通过任何机制注入自己的替代方法接口并让它神奇地使用现有的[Authorize]属性,但是people have done similar things before .

    希望有所帮助!

  • 30

    在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 }
                            });
                }
            }
        }
    }
    

    Edit: 您可能希望在web.config中禁用默认表单身份验证loginUrl - 如果有人忘记您有自定义属性并且错误地使用内置的[Authorize]属性 .

    修改web.config中的值:

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

    然后创建一个记录错误的操作方法“ERROR”,并将用户重定向到您拥有的最通用的登录页面 .

  • 2

    我对此问题的解决方案是自定义 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; }
        }
    

相关问题