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

时间:2021-09-04 17:40:24

I'm creating a multi-tenancy web site which hosts pages for clients. The first segment of the URL will be a string which identifies the client, defined in Global.asax using the following URL routing scheme:

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

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

This works fine, with URLs such as /foo/Home/Index.

对于/foo/Home/Index这样的url来说,这是可行的。

However, when using the [Authorize] attribute, I want to redirect to a login page which also uses the same mapping scheme. So if the client is foo, the login page would be /foo/Account/Login instead of the fixed /Account/Login redirect defined in web.config.

然而,在使用[Authorize]属性时,我希望重定向到同样使用相同映射方案的登录页面。如果客户端是foo,登录页面将是/foo/Account/ login,而不是web.config中定义的固定/Account/ login重定向。

MVC uses an HttpUnauthorizedResult to return a 401 unauthorised status, which I presume causes ASP.NET to redirect to the page defined in web.config.

MVC使用HttpUnauthorizedResult返回401个未经授权的状态,我猜想这可能导致ASP。NET重定向到web.config中定义的页面。

So does anyone know either how to override the ASP.NET login redirect behaviour? Or would it be better to redirect in MVC by creating a custom authorization attribute?

所以有人知道如何重写ASP。网络登录重定向行为呢?还是通过创建自定义授权属性来重定向MVC更好?

EDIT - Answer: after some digging into the .Net source, I decided that a custom authentication attribute is the best solution:

编辑-回答:在深入研究了。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 个解决方案

#1


30  

I think the main issue is that if you're going to piggyback on the built-in ASP.NET FormsAuthentication class (and there's no good reason you shouldn't), something at the end of the day is going to call FormsAuthentication.RedirectToLoginPage() which is going to look at the one configured URL. There's only one login URL, ever, and that's just how they designed it.

我认为主要的问题是,如果您要使用内置的ASP。NET FormsAuthentication类(没有理由不这么做),最后会调用formsauthentic. redirecttologinpage(),它会查看一个已配置的URL。只有一个登录URL,这就是他们设计的方式。

My stab at the problem (possibly a Rube Goldberg implementation) would be to let it redirect to a single login page at the root shared by all clients, say /account/login. This login page wouldn't actually display anything; it inspects either the ReturnUrl parameter or some value I've got in the session or a cookie that identifies the client and uses that to issue an immediate 302 redirect to the specific /client/account/login page. It's an extra redirect, but likely not noticeable and it lets you use the built in redirection mechanisms.

我解决这个问题的方法(可能是Rube Goldberg实现)是让它重定向到所有客户机共享的根上的单个登录页面,例如/account/login。这个登录页面实际上不会显示任何内容;它检查ReturnUrl参数或会话中获得的某个值或标识客户端的cookie,并使用该属性立即向特定/客户端/帐户/登录页面发送302重定向。这是一个额外的重定向,但可能不明显,它允许您使用内置的重定向机制。

The other option is to create your own custom attribute as you describe and avoid anything that calls the RedirectToLoginPage() method on the FormsAuthentication class, since you'll be replacing it with your own redirection logic. (You might create your own class that is similar.) Since it's a static class, I'm not aware of any mechanism by which you could just inject your own alternative interface and have it magically work with the existing [Authorize] attribute, which blows, but people have done similar things before.

另一个选项是在描述时创建您自己的自定义属性,并避免调用FormsAuthentication类上的RedirectToLoginPage()方法,因为您将用自己的重定向逻辑替换它。(您可以创建类似的类。)因为它是一个静态类,所以我不知道您可以通过什么机制注入您自己的替代接口,并让它神奇地与现有的[授权]属性一起工作,这是一种打击,但是人们以前也做过类似的事情。

Hope that helps!

希望会有帮助!

#2


40  

In the RTM version of ASP.NET MVC, the Cancel property is missing. This code works with ASP.NET MVC RTM:

在RTM版本的ASP中。NET MVC,取消属性缺失。这段代码适用于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: You may want to disable the default forms authentication loginUrl in web.config - in case somebody forgets you have a custom attribute and uses the built in [Authorize] attribute by mistake.

编辑:您可能想在web上禁用默认表单身份验证登录。配置——如果有人忘记了你有一个自定义属性,并且错误地使用了[授权]属性。

Modify the value in web.config:

修改web.config中的值:

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

Then make an action method 'ERROR' that logs an error and redirects the user to the most generic login page you have.

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

#3


2  

My solution to this problem was a custom ActionResult class:

我对这个问题的解决方案是一个定制的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; }
    }

#1


30  

I think the main issue is that if you're going to piggyback on the built-in ASP.NET FormsAuthentication class (and there's no good reason you shouldn't), something at the end of the day is going to call FormsAuthentication.RedirectToLoginPage() which is going to look at the one configured URL. There's only one login URL, ever, and that's just how they designed it.

我认为主要的问题是,如果您要使用内置的ASP。NET FormsAuthentication类(没有理由不这么做),最后会调用formsauthentic. redirecttologinpage(),它会查看一个已配置的URL。只有一个登录URL,这就是他们设计的方式。

My stab at the problem (possibly a Rube Goldberg implementation) would be to let it redirect to a single login page at the root shared by all clients, say /account/login. This login page wouldn't actually display anything; it inspects either the ReturnUrl parameter or some value I've got in the session or a cookie that identifies the client and uses that to issue an immediate 302 redirect to the specific /client/account/login page. It's an extra redirect, but likely not noticeable and it lets you use the built in redirection mechanisms.

我解决这个问题的方法(可能是Rube Goldberg实现)是让它重定向到所有客户机共享的根上的单个登录页面,例如/account/login。这个登录页面实际上不会显示任何内容;它检查ReturnUrl参数或会话中获得的某个值或标识客户端的cookie,并使用该属性立即向特定/客户端/帐户/登录页面发送302重定向。这是一个额外的重定向,但可能不明显,它允许您使用内置的重定向机制。

The other option is to create your own custom attribute as you describe and avoid anything that calls the RedirectToLoginPage() method on the FormsAuthentication class, since you'll be replacing it with your own redirection logic. (You might create your own class that is similar.) Since it's a static class, I'm not aware of any mechanism by which you could just inject your own alternative interface and have it magically work with the existing [Authorize] attribute, which blows, but people have done similar things before.

另一个选项是在描述时创建您自己的自定义属性,并避免调用FormsAuthentication类上的RedirectToLoginPage()方法,因为您将用自己的重定向逻辑替换它。(您可以创建类似的类。)因为它是一个静态类,所以我不知道您可以通过什么机制注入您自己的替代接口,并让它神奇地与现有的[授权]属性一起工作,这是一种打击,但是人们以前也做过类似的事情。

Hope that helps!

希望会有帮助!

#2


40  

In the RTM version of ASP.NET MVC, the Cancel property is missing. This code works with ASP.NET MVC RTM:

在RTM版本的ASP中。NET MVC,取消属性缺失。这段代码适用于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: You may want to disable the default forms authentication loginUrl in web.config - in case somebody forgets you have a custom attribute and uses the built in [Authorize] attribute by mistake.

编辑:您可能想在web上禁用默认表单身份验证登录。配置——如果有人忘记了你有一个自定义属性,并且错误地使用了[授权]属性。

Modify the value in web.config:

修改web.config中的值:

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

Then make an action method 'ERROR' that logs an error and redirects the user to the most generic login page you have.

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

#3


2  

My solution to this problem was a custom ActionResult class:

我对这个问题的解决方案是一个定制的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; }
    }