Cách chuyển hướng đến URL đăng nhập động trong ASP.NET MVC


96

Tôi đang tạo một trang web cho thuê nhiều nơi lưu trữ các trang cho khách hàng. Phân đoạn đầu tiên của URL sẽ là một chuỗi xác định máy khách, được xác định trong Global.asax bằng cách sử dụng lược đồ định tuyến URL sau:

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

Điều này hoạt động tốt, với các URL như / foo / Home / Index.

Tuy nhiên, khi sử dụng thuộc tính [Authorize], tôi muốn chuyển hướng đến trang đăng nhập cũng sử dụng cùng một lược đồ ánh xạ. Vì vậy, nếu khách hàng là foo, trang đăng nhập sẽ là / foo / Tài khoản / Đăng nhập thay vì chuyển hướng cố định / Tài khoản / Đăng nhập được xác định trong web.config.

MVC sử dụng HttpUnauthorizedResult để trả về trạng thái 401 trái phép, mà tôi cho rằng khiến ASP.NET chuyển hướng đến trang được xác định trong web.config.

Vậy có ai biết cách ghi đè hành vi chuyển hướng đăng nhập ASP.NET không? Hoặc sẽ tốt hơn nếu chuyển hướng trong MVC bằng cách tạo thuộc tính ủy quyền tùy chỉnh?

CHỈNH SỬA - Trả lời: sau khi đào sâu vào nguồn .Net, tôi quyết định rằng thuộc tính xác thực tùy chỉnh là giải pháp tốt nhất:

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

2
gần như làm điều tương tự với định tuyến, vì vậy tôi cần điều này! Cảm ơn!
Trevor de Koekkoek

Cảm ơn, tôi đang cố gắng tìm ra cách làm điều gì đó tương tự.
Chance

nó đã cho tôi ý tưởng để thực hiện riêng, cảm ơn rất nhiều!
Alexander Beletsky

3
hãy chắc chắn để thiết lập khu vực = null (hoặc khu vực chính xác) nếu sử dụng MVC 2 trở lên - hoặc nếu không nó sẽ nhận được kế thừa từ trang bạn đã cố gắng đến thăm
Simon_Weaver

Bất kỳ cách nào để làm điều này mà không có MVC?
DARKGuy

Câu trả lời:


30

Tôi nghĩ rằng vấn đề chính là nếu bạn đang đi để cõng trên được xây dựng trong ASP.NET lớp FormsAuthentication (và không có lý do chính đáng, bạn không nên), một cái gì đó vào cuối ngày sẽ gọi FormsAuthentication.RedirectToLoginPage()đó là sẽ để xem một URL đã định cấu hình. Chỉ có một URL đăng nhập, và đó chỉ là cách họ thiết kế nó.

Vấn đề của tôi (có thể là triển khai Rube Goldberg) là để nó chuyển hướng đến một trang đăng nhập duy nhất ở gốc được chia sẻ bởi tất cả các khách hàng, chẳng hạn như / account / login. Trang đăng nhập này sẽ không thực sự hiển thị bất cứ thứ gì; nó kiểm tra thông số ReturnUrl hoặc một số giá trị mà tôi đã có trong phiên hoặc một cookie xác định khách hàng và sử dụng nó để đưa ra chuyển hướng 302 ngay lập tức đến trang / khách hàng / tài khoản / đăng nhập cụ thể. Đó là một chuyển hướng bổ sung, nhưng có thể không đáng chú ý và nó cho phép bạn sử dụng các cơ chế chuyển hướng được tích hợp sẵn.

Tùy chọn khác là tạo thuộc tính tùy chỉnh của riêng bạn khi bạn mô tả và tránh bất kỳ thứ gì gọi RedirectToLoginPage()phương thức trên FormsAuthenticationlớp, vì bạn sẽ thay thế nó bằng logic chuyển hướng của riêng bạn. (Bạn có thể tạo lớp tương tự của riêng mình.) Vì là lớp tĩnh nên tôi không biết về bất kỳ cơ chế nào mà bạn có thể chèn giao diện thay thế của riêng mình và làm cho nó hoạt động một cách kỳ diệu với thuộc tính [Authorize] hiện có, nhưng người ta đã từng làm những điều tương tự trước đây .

Hy vọng rằng sẽ giúp!


đây có lẽ là cách tiếp cận an toàn nhất. việc tạo thuộc tính [MyAuthorize] của riêng bạn là rất nguy hiểm. trừ khi xây dựng của bạn là xác định rằng mọi người không sử dụng được xây dựng trong [Duyệt] thuộc tính bạn có nguy cơ dân (hoặc chính bạn) quên và sử dụng một trong những sai
Simon_Weaver

Trong một số trường hợp, có thể hữu ích khi ghi đè Application_AuthenticateRequest(xem câu trả lời của tôi bên dưới).
turdus-merula

41

Trong phiên bản RTM của ASP.NET MVC, thuộc tính Hủy bị thiếu. Mã này hoạt động với 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 }
                        });
            }
        }
    }
}

Chỉnh sửa: Bạn có thể muốn vô hiệu hóa loginUrl xác thực biểu mẫu mặc định trong web.config - trong trường hợp ai đó quên bạn có thuộc tính tùy chỉnh và sử dụng thuộc tính [Authorize] được tích hợp sẵn do nhầm lẫn.

Sửa đổi giá trị trong web.config:

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

Sau đó, thực hiện một phương pháp hành động 'ERROR' ghi lại lỗi và chuyển hướng người dùng đến trang đăng nhập chung nhất mà bạn có.


2
hãy chắc chắn để thêm {khu vực, null} vào từ điển (hoặc bất kỳ khu vực của bạn được gọi là) nếu sử dụng MVC 2 trở lên - hoặc nếu không nó sẽ nhận được kế thừa từ trang bạn đã cố gắng đến thăm
Simon_Weaver

2

Giải pháp của tôi cho vấn đề này là một ActionResultlớp tùy chỉnh :

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

0

Tuy nhiên, nếu một quyết định sử dụng được xây dựng trong ASP.NET FormsAuthentication, người ta có thể overide Application_AuthenticateRequesttrong Global.asax.csnhư sau:

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;
        }
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.